Summary
Full project scan (cora scan) identified 4 critical security vulnerabilities. All involve insufficient input validation before passing user-controlled data to sensitive operations.
Issues
#32 — Command injection via $EDITOR (src/commands/commit_cmd.rs:377)
Editor command is built by interpolating $EDITOR env var into a shell string executed with sh -c. If EDITOR contains shell metacharacters (e.g. vim; rm -rf /), they will be executed.
Fix: Parse EDITOR into program + args safely. Use Command::new(program).args(args).arg(&tmp_path) instead of sh -c.
#61 — Path traversal in JS/TS import resolver (src/engine/context/resolver.rs:235)
JS import resolver strips ../ prefixes manually, then joins with project_root. Paths with embedded traversal segments (e.g. foo/../../secret) bypass the strip and Path::join happily resolves outside repo.
Fix: Use std::fs::canonicalize() on resolved path and verify it starts with canonicalized project_root prefix.
#62 — Path traversal in symbol resolver (src/engine/context/resolver.rs:141)
resolve_symbols accepts entry.file from resolver helpers and reads via project_root.join(&entry.file). Absolute paths or .. segments escape the repo.
Fix: Same as #61 — canonicalize and verify containment before reading.
#91 — API key file written before restrictive permissions (src/config/loader.rs:438)
save_api_key writes ~/.cora/auth.toml with default umask, then chmods to 0o600 afterward. Brief window where the file is group/world-readable.
Fix: Use OpenOptions + OpenOptionsExt::mode(0o600) to create the file with restrictive permissions from the start.
Affected files
src/commands/commit_cmd.rs
src/engine/context/resolver.rs
src/config/loader.rs
Effort estimate: 1-2 days
Summary
Full project scan (cora scan) identified 4 critical security vulnerabilities. All involve insufficient input validation before passing user-controlled data to sensitive operations.
Issues
#32 — Command injection via
$EDITOR(src/commands/commit_cmd.rs:377)Editor command is built by interpolating
$EDITORenv var into a shell string executed withsh -c. IfEDITORcontains shell metacharacters (e.g.vim; rm -rf /), they will be executed.Fix: Parse
EDITORinto program + args safely. UseCommand::new(program).args(args).arg(&tmp_path)instead ofsh -c.#61 — Path traversal in JS/TS import resolver (
src/engine/context/resolver.rs:235)JS import resolver strips
../prefixes manually, then joins withproject_root. Paths with embedded traversal segments (e.g.foo/../../secret) bypass the strip andPath::joinhappily resolves outside repo.Fix: Use
std::fs::canonicalize()on resolved path and verify it starts with canonicalizedproject_rootprefix.#62 — Path traversal in symbol resolver (
src/engine/context/resolver.rs:141)resolve_symbolsacceptsentry.filefrom resolver helpers and reads viaproject_root.join(&entry.file). Absolute paths or..segments escape the repo.Fix: Same as #61 — canonicalize and verify containment before reading.
#91 — API key file written before restrictive permissions (
src/config/loader.rs:438)save_api_keywrites~/.cora/auth.tomlwith default umask, then chmods to0o600afterward. Brief window where the file is group/world-readable.Fix: Use
OpenOptions+OpenOptionsExt::mode(0o600)to create the file with restrictive permissions from the start.Affected files
src/commands/commit_cmd.rssrc/engine/context/resolver.rssrc/config/loader.rsEffort estimate: 1-2 days