Configuration Poisoning Defense: Five Gates for Coding Agents

    This article examines configuration poisoning in AI coding agents, where a poisoned project convention file can be read and followed across multiple independent implementations. It explains why vendor patches are insufficient, walks through the attack chain, and outlines five defensive gates: entry control, configuration integrity, prompt-execution separation, egress allowlisting, and detection-driven rotation. It also includes a configuration drift check script and a control mapping table.

    An Uncomfortable but Self-Evidencing Observation

    Some security reports conclude that there is no patch the tool vendor can ship. At first glance, this may sound like an excuse for the vendor. The argument, however, rests on a harder observation: the same attack path has been successfully reproduced across multiple independent coding agents built by different teams. According to publicly disclosed testing, one chain was nearly always successful, while another had a success rate around half.

    When the same flaw appears across two unrelated implementations, it stops being “a bug in one product” and becomes a property of what coding agents are.

    A useful analogy for test engineers is the browser and a phishing page. When a browser faithfully renders a forged bank login page, it does everything according to specification. The malicious payload lives in the page, not in the browser, so there is no browser vulnerability to patch. Similarly, a coding agent that strictly follows the project convention file located in the current directory is working exactly as designed.

    This judgment can be contested, but it forces a conclusion that a testing team cannot avoid: if the problem cannot be fixed by a vendor patch, it must become a check inside your own gates.

    How the Attack Chain Lands Step by Step

    Breaking the attack into stages makes it easier to place a checkpoint at each step. A typical chain contains five actions:

    1. A poisoned file enters the download directory. A web page can write a text file into the user’s downloads folder. The file name and contents are chosen by the page, and in many cases no click or confirmation is required. Operating systems already block the path where a downloaded executable runs automatically, so this step looks harmless on its own. But a project convention file is not an executable, and guardrails aimed at executables do not apply to it.

    2. The user launches the agent inside the poisoned directory. This step depends on habit rather than a vulnerability. In everyday work, many people invoke coding agents directly in download or temporary directories to process files quickly, which places the poisoned file inside the scope of files the agent reads for project rules.

    3. The agent reads the convention file as a project specification and follows it. The spec file contains a seemingly normal “local development environment setup” instruction that induces the agent to modify its own global configuration, for example by pointing a setting to a malicious source or replacing the default command.

    4. The global configuration is silently rewritten. Once the global layer is poisoned, later sessions inherit the tampered default behavior. The contamination escalates from a single session to persistent state.

    5. A malicious dependency is installed or triggered. Following the rewritten configuration, the agent pulls an unknown third-party dependency package and executes its install script. The attack loop is now closed.

    The key point is that every step from one to five looks like a compliant operation from the agent’s perspective. That is why single-point blocking is hard and layered defense is required.

    Why Five Layers Are Needed Instead of One Patch

    Since a vendor patch is not dependable, defense must move down to the boundaries you control. The five types of detection below map to different stages of the attack chain. They must be layered together to cover the full path. Their principle is: do not trust instructional content coming from the working directory, and add friction to privileged actions.

    1. Entry Control: Govern Where Files Come From

    The starting point is that a poisoned file has landed in the agent’s working directory. Practical controls include:

    • Separate trusted directories. Mark download, temporary, and shared directories as untrusted workspaces. When launching a coding agent there, force a risk prompt or disable automatic loading of spec/convention files by default.
    • Validate the source of convention files. Automatically load a convention file only when it comes from a trusted project repository and carries a trusted signature or hash. Keep default suspicion for convention files that appear alone and have no version history.
    • Audit-on-write. Tag files written into local directories by web or non-interactive scenarios, distinguish them from files created by the user, and allow downstream read operations to make decisions based on that metadata.

    2. Configuration Integrity: Prevent Your Own Settings from Being Changed

    The high-risk action in the attack is modifying the agent’s global configuration. The defense is to make configuration drift detectable:

    • Put the global configuration under version control and signing. Create a baseline snapshot of the global config file and record hashes. Any deviation from the baseline should trigger an alert.
    • Run with least privilege. Run the agent under a restricted account and restricted file-system permissions so that rewriting user-level global configuration is blocked at the permission layer rather than relying on the agent’s self-restraint.
    • Make critical settings read-only. Set key fields such as dependency sources, command mappings, and network policies to read-only, or manage them through external policy, and prohibit in-session modification.

    3. Prompt and Execution Separation: Do Not Let Text Become Action

    This is the most easily overlooked layer, but it addresses the root cause. The core idea is that declarative content and imperative execution must be separated; text inside a configuration file should not automatically gain execution semantics.

    • Treat convention files as data, not instructions. A convention file should only provide context. Any imperative such as “run this command,” “change this setting,” or “install this package” should be downgraded to a suggestion awaiting human confirmation.
    • Decouple actions from their source. High-impact actions such as installing dependencies, changing global settings, or making network requests must go through independent human confirmation or policy approval, regardless of whether the instruction comes from a prompt or a configuration file. They do not become exempt because the file says so.
    • Resolve conflicts conservatively. If the prompt says “do not execute” while a configuration file implies “execute,” the system should favor the more conservative side rather than let execution intent win. This is exactly the contradiction in the title: a prohibition in the text layer must take precedence over an inducement in the file layer.

    4. Egress Allowlisting: Narrow the Outbound Data Path

    For the attack to cause real harm, such as pulling packages or exfiltrating data, it often relies on network egress:

    • Default-deny egress policy with on-demand allowlisting. Limit the agent runtime’s outbound access to an explicit allowlist, permitting only domains or endpoints required for business.
    • Enforce dependency source pinning. When installing third-party dependencies, allow only trusted mirrors or internal artifact repositories, and block unknown or newly appearing registries.
    • Add friction to install scripts. Do not automatically execute dependency postinstall scripts; require explicit confirmation to avoid “pull and execute.”

    5. Detection and Rotation: Encode the Response into the Process

    Even if earlier layers are bypassed, the goal is to keep the loss controllable and stop the bleeding quickly:

    • Use credentials just in time and rotate them. Any token or key that may be readable by the agent should be short-lived. Once an abnormal access path is detected, revoke and rotate immediately rather than fixing it after the fact.
    • Predefine response playbooks. Treat detected configuration drift, abnormal installation, or abnormal egress as explicit triggers and bind them to fixed actions such as isolation, rollback, alerting, and rotation, avoiding ad hoc judgment.
    • Maintain traceability. Record the source and hash of every configuration read, write, and execution so incidents can be reconstructed and gates can be improved continuously.

    Appendix: Configuration Drift Check Script

    The script below is illustrative. It takes a baseline snapshot of the global configuration and alerts when drift is detected. Adjust paths and hash algorithms for your own environment, and do not use it directly in production.

    1. #!/usr/bin/env bash
    2. # Configuration drift check: compare current configuration with baseline snapshot hash
    3. set -euo pipefail
    4. CONFIG_DIR="${CONFIG_DIR:-$HOME/.config/agent}" # Agent global configuration directory
    5. BASELINE="$CONFIG_DIR/.baseline.sha256"
    6. REPORT="${REPORT:-/tmp/config_drift_report.txt}"
    7. if [[ ! -d "$CONFIG_DIR" ]]; then
    8. echo "Configuration directory does not exist; skipping check" >&2
    9. exit 0
    10. fi
    11. snapshot() {
    12. # Include only key configuration files and output a stable hash manifest
    13. find "$CONFIG_DIR" -maxdepth 1 -type f \
    14. ! -name '.baseline.sha256' \
    15. -print0 | sort -z | xargs -0 sha256sum
    16. }
    17. if [[ ! -f "$BASELINE" ]]; then
    18. snapshot > "$BASELINE"
    19. echo "Baseline snapshot created: $BASELINE"
    20. exit 0
    21. fi
    22. CURRENT="$(mktemp)"
    23. snapshot > "$CURRENT"
    24. if diff -u "$BASELINE" "$CURRENT" > "$REPORT"; then
    25. echo "No configuration drift detected. State is normal."
    26. rm -f "$CURRENT"
    27. else
    28. echo "Configuration drift detected! See $REPORT" >&2
    29. # This should integrate with an alerting system and trigger the response playbook
    30. exit 2
    31. fi

    The common operational practice is to run this script as a scheduled task or a pre-session hook, and to place the baseline file itself under version control or protected read-only storage so the baseline cannot be tampered with as well.

    Control Mapping Table

    Attack chain stage Risky action Detection/control Control layer
    File drop Poisoned file enters working directory Mark untrusted directories, validate source, audit-on-write Entry control
    User launch Agent invoked from poisoned directory Risk prompt for untrusted workspace or block automatic loading Entry control
    Read and execute Convention file treated as instruction Treat spec files as data, downgrade imperatives to suggestions Prompt/execution separation
    Config rewrite Global settings silently modified Version-controlled config + hash baseline, read-only settings, least privilege Configuration integrity
    Dependency pull Malicious third-party package installed Artifact repository lock, installation script confirmation Egress allowlisting
    Data exfiltration Callback or connection to external endpoint Default-deny egress + allowlist Egress allowlisting
    Post-incident handling Credential leakage, persistent contamination Short-lived credentials, rotate on discovery, predefined response playbook Detection and rotation

    Conclusion

    The real difficulty with this class of risk is not technical complexity. It is that every individual action can look compliant. A single-point patch is therefore destined to fail. The only practical route is layered defense: do not trust instructional content from the working directory, fully decouple declarative text from execution, and turn configuration integrity, egress scope, and response flow into automatable, auditable gate checks. For testing and security teams, putting these controls into gates is more realistic and more reliable than waiting for a vendor patch that may never arrive.