fix: harden path traversal, env injection, and tool security defenses - #77
Merged
Merged
Conversation
Reject HOME values containing '..' path segments at startup and add a defense-in-depth prefix check in writeConfigFile to ensure the resolved config directory stays under $HOME/.astrid/plugins/. Closes #59
Manifest env: entries are applied to the child process with no filtering. A malicious manifest could override HOME, PATH, NODE_OPTIONS, etc. to escape the sandbox. Block these with a warning until the install-time elicitation flow is implemented. Part of #59
- bridge: refuse to start when HOME is unset instead of falling back to world-writable /tmp - plugins: expand blocked env var list with proxy vars, TMPDIR, TLS/CA cert overrides (NODE_EXTRA_CA_CERTS, SSL_CERT_*) - hooks: prevent custom env from overriding sandboxed allowlist vars (PATH, HOME, etc.) in CommandHandler - core: reject '..' path components in HOME and ASTRID_HOME in AstridHome::resolve() - mcp: add env var blocklist for library/code injection vars in connect_stdio_server() Part of #59
- hooks: add BLOCKED_HOOK_ENV list and is_blocked_hook_env() to prevent LD_PRELOAD, NODE_OPTIONS, BASH_ENV, OPENSSL_CONF, and LD_/DYLD_/ npm_config_ prefix injection in sandboxed hooks - hooks: extract apply_env() helper to satisfy clippy::too_many_lines - mcp: align server blocklist with the plugin blocklist (add HOME, PATH, ASTRID_HOME, proxy vars, TLS/CA vars, TMPDIR, OPENSSL_CONF) - plugins: add ASTRID_HOME, OPENSSL_CONF to blocklist; add LD_/DYLD_/ npm_config_ prefix blocking - core: fix test pollution — add EnvGuard RAII type so HOME is restored even on panic unwind Part of #59
Addresses all findings from three parallel security/correctness/architecture reviews of the home-path-traversal branch. Critical fixes: - Fix UTF-8 panic in read_file line truncation (char boundary check) - Remove double spark onboarding call (main.rs + chat.rs) - Wrap blocking flock in spark_tool with spawn_blocking - Use EnvGuard RAII in all env-mutating tests (panic-safe cleanup) Security hardening: - Extract shared env_policy module in astrid-core with comprehensive blocklist (union of hooks/MCP/plugins lists + prefix matching) - Replace all three inline blocklists with shared is_blocked_spawn_env() - Validate HOME is absolute before use (matching ASTRID_HOME guard) - Filter context env vars through blocklist in hook sandbox - Validate HOME before relaying to hook child processes - Enforce absolute paths in read_file, write_file, edit_file tools - Fix JS bridge path separator for Windows (use path.sep) Minor improvements: - Add gateway SparkConfig field-parity test - Add SparkLockGuard RAII with lock file cleanup on drop - Sanitize spark before format_spark in evolve response - Document spark preamble + custom prompt interaction Also includes spark agent identity feature (onboarding, config, tool, system prompt integration).
native-tls 0.2.17 has a non-exhaustive match bug on newer Rust toolchains. astrid-llm was overriding the workspace reqwest (which uses rustls-tls) with bare defaults that pulled in native-tls. teloxide also defaulted to native-tls. Switch both to use workspace deps with rustls, eliminating native-tls entirely.
Member
Author
|
Weird. Not sure what happened, but a dependency appears to be failing for all PRs now and I don't know if this is some weird dependency chain attack which I'm unsure is possible. Before, this all was working fine with this dependency. Anyways, I'll include it into this PR, and rebase all other PRs on top of this one. |
Member
Author
|
Related to the failed check and clippy: rust-native-tls/rust-native-tls#367 Will switch to rustls. |
75 tasks
This was referenced Aug 31, 2026
Open
Closed
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.
Closes #59
Summary
Comprehensive security hardening addressing path traversal via
$HOME/$ASTRID_HOME, environment variable injection across hooks/MCP/plugins, and tool input validation. Includes the spark agent identity feature.Critical fixes
read_file— line truncation now uses char-boundary-safe slicing instead of raw byte offsetrun_spark_onboarding()call (was in bothmain.rsandchat.rs)spark_toolevolve action wrapped inspawn_blockingto avoid stalling TokioEnvGuardRAII for panic-safe cleanupSecurity hardening
astrid_core::env_policymodule with comprehensive blocklist (union of all three inline lists +ld_/dyld_/npm_config_prefix matching). Replaces divergent inline lists in hooks, MCP server, and pluginsHOMEnow checked withis_absolute()matching the existingASTRID_HOMEguardcontext.to_env_vars()through the blocklist (previously bypassed all filtering)HOMEvalidated for traversal before passing to hook child processesread_file,write_file,edit_filetools reject non-absolute pathspluginConfigBasecheck usespath.sepinstead of hardcoded"/"Minor improvements
SparkConfigfield-parity testSparkLockGuardRAII with lock file cleanup on dropformat_sparkin evolve responseOut-of-scope issues filed
truncate_outputUTF-8 panic at 30KB boundarysafe_descriptionUTF-8 panic at 200-byte boundaryworkspace_pathunvalidated from session fileTest plan
cargo check --workspace— 0 errors, 0 warnings (except pre-existing QuickJS placeholder)cargo test --workspace— all tests pass (1400+ across all crates)cargo fmt --check— no formatting issuesastrid chatread_filewith emoji-heavy file >2000 bytes/line doesn't panicread_file/write_file/edit_file