Skip to content

Whitelist create_bulk_envs() fields to stop resourceable hijacking - #199

Merged
Terrence721 merged 5 commits into
mainfrom
fix/services-bulk-envs-mass-assignment
Aug 21, 2026
Merged

Whitelist create_bulk_envs() fields to stop resourceable hijacking#199
Terrence721 merged 5 commits into
mainfrom
fix/services-bulk-envs-mass-assignment

Conversation

@Terrence721

@Terrence721 Terrence721 commented Aug 21, 2026

Copy link
Copy Markdown
Owner

Summary

Found via a fresh /code-review pass on app/Http/Controllers/Api/ServicesController.php (issue #70). Closes 2 findings from that pass - they collapse into one fix because they're the exact same line of code.

Finding 1 (security): create_bulk_envs() passed the raw request item straight through as updateOrCreate()'s $values argument. EnvironmentVariable's resourceable_id/resourceable_type are both $fillable, and the validator only checks key/value/is_literal/is_multiline/is_shown_once/comment - it never rejects unknown fields, unlike create_service()/update_by_uuid(), which explicitly diff the request against an allowed-fields list.

Verified against the actual Eloquent implementation in this Laravel version: the create-new-row path is already safe - HasOneOrMany::create() calls setForeignAttributesForCreate() after newInstance($attributes), so the correct resourceable_id/resourceable_type always win regardless of attacker input. But the update-existing-row path in updateOrCreate() calls $instance->fill($values)->save() unconditionally, with no re-application of the foreign/morph attributes - a caller who already knows (or can enumerate) an existing env var's key can retarget it onto an arbitrary resource, including one owned by a different team.

Finding 2 (correctness): the normalized $key computed for the updateOrCreate() lookup was discarded on save, since the raw $item['key'] (un-normalized) rode along in $item and got re-applied by fill().

Fix

Build an explicit $values array from only the validated fields (key set to the already-normalized $key, value, and the optional booleans/comment only when present), matching the pattern create_env()/update_env_by_uuid() already use, instead of passing the raw request item through. This one change closes both findings.

Verification

TDD-proved, both tests confirmed failing against the pre-fix code and passing after:

  • ignores an attacker-supplied resourceable_id/resourceable_type when bulk-updating an existing env var
  • keeps the normalized key when bulk-updating an existing env var with a raw un-normalized key

All 15 tests in ServicesEnvsTest.php pass. Pint/PHPStan clean on the changed file.

claude and others added 5 commits August 21, 2026 07:14
updateOrCreate() passed the raw request item straight through as
$values. On the update-existing-row path, fill($values)->save() then
applied it unconditionally, letting a caller retarget an env var's
resourceable_id/resourceable_type onto an arbitrary resource -
including one owned by a different team. The create-new-row path was
already safe (Eloquent re-applies the correct foreign/morph attributes
after fill on create), so only the update path was exploitable.
Same root cause as the resourceable-hijacking fix: the previous
commit's whitelist change also fixes this for free, since $values
now explicitly carries the normalized $key instead of $item's raw one.
…s-mass-assignment

# Conflicts:
#	tests/v4/Feature/Api/ServicesEnvsTest.php
@Terrence721
Terrence721 merged commit a617b3a into main Aug 21, 2026
9 checks passed
@Terrence721 Terrence721 mentioned this pull request Aug 21, 2026
77 tasks
@Terrence721
Terrence721 deleted the fix/services-bulk-envs-mass-assignment branch August 21, 2026 12:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants