Skip to content

fix(security): add path-containment guards to script CLI path inputs - #2162

Open
0xDEnYO wants to merge 2 commits into
mainfrom
fix/aikido-path-guards
Open

fix(security): add path-containment guards to script CLI path inputs#2162
0xDEnYO wants to merge 2 commits into
mainfrom
fix/aikido-path-guards

Conversation

@0xDEnYO

@0xDEnYO 0xDEnYO commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Which Linear task belongs to this PR?

Fixes EXSC-731

Why did I implement it this way?

This PR resolves the 21 open Aikido "Potential file inclusion attack via reading file" findings whose flagged input genuinely is free-form (CLI-supplied path fragments with no upstream allow-list validation), using the same containment-guard pattern PR #2143 established for getDeployLogFile: resolve against the intended base directory, then reject any path whose path.relative(base, …) escapes it.

  • propose{PolymerCCTP,AllBridge,DeBridgeDln,MegaETH}… (4 identical local getDeploymentsFilePath copies): --network is interpolated into deployments/<network>[.staging].json before any networks.json validation happens (isTestnetNetwork() returns false for unknown names rather than throwing). The guard lives inside the shared-shape helper so both the existsSync and readFileSync sites in each file are covered.
  • getFunctionSelectors (script/utils/viemScriptHelpers.ts): same guard fix(security): AI Fix for Potential file inclusion attack via reading file #2143 added to getDeployLogFile two functions below, applied to the out/<contractName>.sol/<contractName>.json path.
  • generateHexagateImportCsv.ts: --networks CSV entries are read as deployments/<n>.diamond.json in the same Promise.all that loads networks.json, i.e. before the unknown-network skip can run — names are now containment-checked at parse time.
  • tasks/generateLedgerClearSigning.ts: all path args (--ledgerFilePath, --outputFilePath, --proposalFilePath, --facetsDir, --foundryOutDir, --deploymentsDir, --networksJson) now resolve through a resolveWithinCwd() helper. Every legitimate invocation stays inside the working directory: repo defaults locally, and ledger-registry/<path> in syncLedgerClearSigning.yml (the registry clone is a subdirectory of the workspace).

Guards were falsified against real inputs: --networks '../../etc/passwd' and --networks '../secrets'Invalid network name, --ledgerFilePath '../../../etc/hosts'Path escapes the working directory, getFunctionSelectors('../../foundry.toml/x')Invalid contract name; happy paths (--networks mainnet CSV generation, valid contract name reaching the artifact lookup) confirmed unchanged.

Findings where the catalogue's false-positive rationale is actually true for the call site (repo-derived walks, assertSafePathSegment-sanitized names, networks.json-validated inputs, mktemp-file reads) were ignored in Aikido with per-call-site reasons instead of guarding — a cwd-containment guard would have broken legitimate flows like diamondUpdateFacet.sh's mktemp calldata file.

Checklist before requesting a review

Checklist for reviewer (DO NOT DEPLOY and contracts BEFORE CHECKING THIS!!!)

  • I have checked that any arbitrary calls to external contracts are validated and or restricted
  • I have checked that any privileged calls (i.e. storage modifications) are validated and or restricted
  • I have ensured that any new contracts have had AT A MINIMUM 1 preliminary audit conducted on by <company/auditor>

Contain free-form path-building inputs the same way #2143 did for
getDeployLogFile: network names in the four propose*Mappings scripts
[aikido:286911101,286911102,434639614,434639616,154847648,154847649,161720063,161720065]
and generateHexagateImportCsv [aikido:222857805], contract names in
getFunctionSelectors [aikido:152923770,152923771], and all path args of
generateLedgerClearSigning [aikido:277413157..277413168].

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The change adds containment checks for network-derived deployment paths, compiled contract paths, and ledger command paths. It also updates path-traversal matching guidance with supported validation and sanitization cases.

Changes

Path containment validation

Layer / File(s) Summary
Path-traversal matching guidance
.agents/references/aikido-false-positive-catalog.md
The catalog documents validated, sanitized, repository-derived, and containment-guarded paths. It excludes unvalidated free-form paths.
Deployment path guards
script/tasks/generateHexagateImportCsv.ts, script/tasks/propose*ChainIdMappings.ts, script/tasks/proposeMegaETHBridgeRegistrations.ts
Network-derived deployment paths are resolved within the deployments directory. Traversal and absolute paths now raise errors.
Build-output and ledger path guards
script/utils/viemScriptHelpers.ts, tasks/generateLedgerClearSigning.ts
Compiled contract paths and ledger inputs, outputs, and related directories are validated against their permitted boundaries.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested labels: requires-types

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely summarizes the primary security change: adding path-containment guards to script CLI inputs.
Description check ✅ Passed The description includes the Linear task, implementation rationale, change details, validation results, and required checklist sections.
✨ Finishing Touches 💡 2
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🛠️ Fix failing CI checks 💡
  • Fix failing CI checks
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/aikido-path-guards

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…alog pattern

Gate-review findings on this PR: the exported getFunctionSelectors gained a
new throw branch without a JSDoc @throws tag (same gap fixed for
getDeployLogFile after #2143), and the catalog's path_traversal_scripts
entry overclaimed SupportedChain typing for call sites that take plain
strings — narrowed so free-form CLI paths get guards, not ignores.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@0xDEnYO

0xDEnYO commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

🔒 Gate review (local trial) — residual findings

Auto-fixed in 2089576d4: missing @throws on getFunctionSelectors (confidence 89); catalog path_traversal_scripts narrowed (task-mandated — the old text overclaimed SupportedChain typing for plain-string call sites and was used to dismiss these exact findings in PRs #1847/#2075).

Watch item (from git history): the byte-identical guard on proposeAllBridgeChainIdMappings.ts was added and reverted on 2026-07-24 (edd5301e93961b3cdd) because Aikido re-rated the guard itself as a NEW HIGH finding and failed the security gate — while #2143's identical guard merged green on 2026-07-30. This PR's "Aikido Security: check code" is skipping while draft; verify it after flipping ready. Fallback if it re-triggers: allow-list regex style per assertSafePathSegment (script/deploy/tron/helpers/tronscanVerify.ts).

Lower-confidence — human judgment (60–79, not acted):

  • Tests (72): no unit tests for the new guards; fix(security): AI Fix for Potential file inclusion attack via reading file #2143 added traversal tests to viemScriptHelpers.test.ts for the identical pattern. Guards were instead falsified live (144 legit network shapes pass; 1,880-name fuzz on the hexagate suffix question; all 7 ledger path args attacked individually; CI invocation shape end-to-end).
  • Hexagate header (62): the module-header usage doc doesn't mention the new --networks hard-throw, and the throw surfaces as a raw stack trace via main().catch instead of the file's Usage-style error.

Dropped (<60): extracting a shared guard helper (48 — inline matches the merged #2143 precedent; valid follow-up refactor), error-message style drift in resolveWithinCwd (36), unguarded --output-dir/--prefix write paths (12 — documented feature, out of scope).

@0xDEnYO
0xDEnYO marked this pull request as ready for review July 31, 2026 04:17
@0xDEnYO

0xDEnYO commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@script/utils/viemScriptHelpers.ts`:
- Around line 363-371: Replace the prefix-only parent-directory checks with
segment-aware checks that reject only a relative path equal to ".." or beginning
with "..${path.sep}", while retaining the absolute-path check. Apply this
containment predicate in script/utils/viemScriptHelpers.ts lines 363-371,
script/tasks/generateHexagateImportCsv.ts lines 162-170,
script/tasks/proposeAllBridgeChainIdMappings.ts lines 76-80,
script/tasks/proposeDeBridgeDlnChainIdMappings.ts lines 73-77,
script/tasks/proposeMegaETHBridgeRegistrations.ts lines 73-77,
script/tasks/proposePolymerCCTPChainIdMappings.ts lines 76-80, and
tasks/generateLedgerClearSigning.ts lines 136-142; add regression coverage there
for accepting "..name" descendants and rejecting "../" escapes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5872a68b-14b3-420b-884d-e47c32a28d01

📥 Commits

Reviewing files that changed from the base of the PR and between c72ce47 and 2089576.

📒 Files selected for processing (8)
  • .agents/references/aikido-false-positive-catalog.md
  • script/tasks/generateHexagateImportCsv.ts
  • script/tasks/proposeAllBridgeChainIdMappings.ts
  • script/tasks/proposeDeBridgeDlnChainIdMappings.ts
  • script/tasks/proposeMegaETHBridgeRegistrations.ts
  • script/tasks/proposePolymerCCTPChainIdMappings.ts
  • script/utils/viemScriptHelpers.ts
  • tasks/generateLedgerClearSigning.ts

Comment thread script/utils/viemScriptHelpers.ts
@0xDEnYO 0xDEnYO closed this Jul 31, 2026
@0xDEnYO
0xDEnYO deleted the fix/aikido-path-guards branch July 31, 2026 05:15
@0xDEnYO
0xDEnYO restored the fix/aikido-path-guards branch July 31, 2026 05:17
@0xDEnYO 0xDEnYO reopened this Jul 31, 2026
@0xDEnYO
0xDEnYO enabled auto-merge (squash) July 31, 2026 05:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants