fix(security): scoped binding + recursive tx integrity + aligned detach (BC)#97
Merged
Conversation
PR Summary
|
…ch (BC) Three corrective fixes to AAuth core lifecycle and service layer, all backward compatible — composer update on existing 21.x projects will not break a working host application, and PHP-FPM behaviour is byte-equivalent. 1. SECURITY (HIGH): AAuth container binding now uses scoped() instead of singleton(), so Laravel Octane/Vapor workers no longer leak one user's AAuth state (user, role, organization node IDs, permissions, ABAC rules, super-admin flag) into the next user's request. PHP-FPM is unaffected. 2. RELIABILITY: OrganizationService::updateNodePathsRecursively and deleteOrganizationNodesRecursively now wrap recursion in DB::transaction() with savepoints. Previously they swallowed exceptions and committed the outer transaction anyway, leaving subtrees in an inconsistent state. Public signatures (including $withDBTransaction parameter) preserved. 3. API CONSISTENCY (BC-safe): added detachOrganizationRoleFromUserBy() with parameter order matching attachOrganizationRoleToUser(). The existing detachOrganizationRoleFromUser() remains in place, fully working, marked @deprecated in docblock only (no runtime notice). To be removed in next major release. Tests: 137 passing, 274 assertions. Added OctaneScopingTest (6 tests including SECURITY regression cases for cross-user property and super- admin leak), TransactionIntegrityTest (7 tests including deep-recursion rollback and caller-managed transaction integration). Filled todos in RolePermissionServiceTest (updateRole, deleteRole, activateRole, deactivateRole) and AAuthTest (passOrAbort, organizationNode, static switchableRoles). TestCase.php now respects DB_CONNECTION env (phpunit.xml.dist defaults to mysql for CI; local devs can override). Tests pass against MariaDB locally and MySQL 8.0 on GitHub Actions matrix. OpenSpec change: openspec/changes/fix-critical-auth-bugs/ Main spec synced: openspec/specs/core-rbac/spec.md (1 modified, 3 added requirements). README updated with Octane note. UPGRADE.md documents 21.1.0 migration recipe for all three fixes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Moved openspec/changes/fix-critical-auth-bugs/ to openspec/changes/archive/2026-05-22-fix-critical-auth-bugs/ now that implementation is complete (main spec was already synced in the previous commit, so --skip-specs was used during archival). - Removed .github/workflows/claude-code-review.yml: the Claude Code Action reports the org's Claude subscription is disabled for Code on this repo, causing every PR run to fail. Re-add (or replace with the API-key variant) once subscription access is sorted out. - No composer dependency bumps in this PR: `composer outdated --direct` only surfaces major-version bumps (Laravel 13, Pest 4, PHPUnit 13, Testbench 11). Those are intentionally deferred to dedicated PRs to keep this security fix isolated. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
718c582 to
386ece3
Compare
…Node::create The composer update (Laravel 10 → 12, Larastan upgrade) surfaced a stricter type check on OrganizationService::createOrganizationNode line 106: passing a generic `array` to OrganizationNode::create() now fails because Larastan expects `array<model property of OrganizationNode, mixed>`. Fix: build the attributes array with the fillable column names as literal keys before passing to create(). Behaviour is byte-equivalent — same columns are populated from the same input keys — but PHPStan can now verify the shape statically. Verified: - vendor/bin/phpstan analyse --memory-limit=1G → no errors - vendor/bin/pest → 137 passed (274 assertions) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three corrective fixes to AAuth core lifecycle and service layer. All backward compatible —
composer updateon existing 21.x projects will not break a working host application, and PHP-FPM behaviour is byte-equivalent to today.1. SECURITY (HIGH severity) — Octane/Vapor cross-request state leak
Reported by a production consumer running on Laravel Octane. The
aauthcontainer binding was asingleton, so a long-lived worker reused User A's resolvedAAuthinstance (carrying\$user,\$role,\$organizationNodeIds, permissions, ABAC rules, super-admin flag) for User B's subsequent request → authorization bypass, super-admin escalation, PII leak.Fix:
\$this->app->scoped('aauth', ...). Laravel 9+ flushes scoped bindings onRequestTerminated. PHP-FPM unaffected (every request is a fresh process). Seesrc/AAuthServiceProvider.php:63.2. RELIABILITY — silent transaction corruption in recursive ops
OrganizationService::updateNodePathsRecursivelyanddeleteOrganizationNodesRecursivelyopened a transaction, swallowed any exception in catch, then calledcommit()anyway → subtree left half-modified, caller never knew.Fix: wrap recursion in
DB::transaction()(savepoints handle nesting natively). Public signatures (including\$withDBTransactionparameter) preserved. Exceptions now propagate to the caller; everything else byte-equivalent.3. API CONSISTENCY (BC-safe) — aligned-order detach method
detachOrganizationRoleFromUser(\$userId, \$roleId, \$nodeId)takes parameters in inverse order fromattachOrganizationRoleToUser(\$nodeId, \$roleId, \$userId). Re-ordering would silently corrupt data for every consumer.Fix: added new
detachOrganizationRoleFromUserBy(\$nodeId, \$roleId, \$userId)with aligned order. Legacy method kept, no runtime notice emitted — only@deprecateddocblock so IDEs and PHPStan flag call sites. To be removed in next major.Test plan
New test files
Files changed
BC contract verified
composer updateon any 21.x → working host app keeps workingOrganizationServicerecursive methods which now propagate previously-swallowed errors — a documented intentional fix)🤖 Generated with Claude Code