fix(bundle): Solidity loader post-merge review: untrusted dependencies, forge/solc fidelity - #177
Merged
Merged
Conversation
…ies, forge/solc fidelity Security (dependencies are input the project didn't write): - An import must resolve to a .sol file inside the bundle root: `import ".env";` (bare or relative) and remapping targets like `/opt/x/` or `../x/` are refused. - A dependency's import (forge libs, Soldeer dependencies/, git submodules, node_modules) must land, by real path, on a dependency's file: no project file through a relative path, a base-path lookup, its own remappings or a symlink. - A dependency's foundry.toml whose `extends` lies outside it is skipped. - --manifests drops [rpc_endpoints]/[etherscan] and secret-named keys from .toml configs, strips URL credentials from every carried file, carries only .toml/.txt configs, and no longer carries hardhat.config.* (code with keys). - Refusals are fatal and say why. Fidelity: - Legacy top-level [<name>] profiles, case-insensitive profile names, quoted dotted table names and TOML string escapes (checked against forge v1.8.3). - --mapping keeps forge's library lookups and honours the mapping's `extends` and a top-level `remappings`; a root remappings.txt without foundry.toml applies as written (solc/Hardhat), with one it is slash-terminated (forge). - Library lookups start at the importer directory's parent and come before the base path, as foundry-compilers resolves them. - Directory entries follow symlinks exactly like walkdir (checked against the crate on 428 random trees); a missing or empty entry dir is skipped. - The scanner ends // comments at \r and reads string escapes as UTF-8 bytes (checked against solc-js 0.8.30). - FOUNDRY_PROFILE / FOUNDRY_REMAPPINGS are reported when they apply; buildBundle and bundleCommand take `env`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C6oBS5QX4oqZcd2d3STiGA
This was referenced Sep 28, 2026
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.
Follow-up to #176. A post-merge review of the Solidity loader listed 15 findings. I reproduced each against
main(6762667) and checked the forge and solc claims against the real tools:14 findings held as reported, and I fixed them. For finding 9 the reviewer's forge claim was half wrong; it is fixed to match what forge actually does. Details are below.
Security
Dependencies are input the project didn't write. On
main, a dependency underlib/containingimport ".env";put the project's.envinto the bundle with no flag at all..solfile inside the bundle root.import ".env";, a relativeimport "../../../.env";(a variant that predates Implement Foundry remappings discovery for Solidity imports #176), and remapping targets such asx/=/opt/evil/(finding 5, which used to produce a bundle thatstasis extractrejects) or../elsewhere/.Unresolved import: .env from lib/evil/src/E.sol (refused: it resolves to .env, which is not a .sol file).libs, Soldeer'sdependencies/, a git submodule from.gitmodules, or anynode_modules.steal/=../../secrets/case);import "script/Secrets.sol", a variant the review didn't list);ds-testis the usual case.foundry.tomlwhoseextendspoints outside it is skipped, with a warning (finding 3).--manifestsno longer carries credentials (finding 4)..tomlconfigs lose their[rpc_endpoints]and[etherscan]tables, whether at the top level or inside a profile.eth_rpc_url,etherscan_api_keyand any other key named like a key, token, secret or password. Everything else in the file is kept verbatim..gitmodules, the lock files andpackage.json.*.toml/*.txtconfig files are carried.hardhat.config.*is not carried any more: it is code and may hold keys.Wrong resolution compared with forge or solc
[default]table; top-levelremappings[<name>]tables are read as profiles, with[profile.<name>]winning key by key; checked against forge. forge itself rejects a top-levelremappings = […], so it is accepted only in a--mappingfile, which is how stasis read such files before #176.FOUNDRY_PROFILEor a remapping variable shaped the result, andbuildBundle/bundleCommandacceptenv. The bundle format still doesn't record them; that would need a format change.@oz/=lib/ozmakes@oz/X.solresolve tolib/ozX.sol). Next to a foundry.toml it is slash-terminated, as forge reads it.--mappingturns off library lookups and ignoresextends--mappingnow changes only the remappings.FOUNDRY_PROFILEis case-sensitive[profile.CI]withci, andCIwith[profile.ci]), checked against forge.stasis bundle src test scriptfails withoutscript/no such file or directory.resolve_absolute_librarydoes, and are tried before the base-path lookup, in the same order foundry-compilers uses.\rand misdecodes\xNN//comment ends at\ras well as\n, and string escapes are decoded as UTF-8 bytes ("\xc3\xa9"isé). An unterminated literal no longer lets a later string be taken as the import path. All three checked against solc-js.[profile."ci.fast"]is one profile, and\uXXXX,\UXXXXXXXX,\nand the other escapes decode.../that climbs above the root is rejected, while solc clamps itVerification
.solfiles, outside-root targets, a dependency's own remapping, base-path lookup and symlink;envpassthrough;--mappingwith libs,extendsand a top-levelremappings;\r,\xNNand unterminated-string cases.mainon the 6,314.solfiles on the machine (36.6 MB). None of them has a CR-only line break or a\ximport path.oxlintis clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01C6oBS5QX4oqZcd2d3STiGA
Generated by Claude Code