Merge pull request #2 from gavrielc/claude/fix-dotenv-exposure-LEzJ8
Fix security: only expose auth vars to containers, not full .env
This commit is contained in:
@@ -82,7 +82,7 @@ cat .env # Should show one of:
|
|||||||
|
|
||||||
**Apple Container Bug:** Environment variables passed via `-e` are lost when using `-i` (interactive/piped stdin).
|
**Apple Container Bug:** Environment variables passed via `-e` are lost when using `-i` (interactive/piped stdin).
|
||||||
|
|
||||||
**Workaround:** The system mounts `.env` as a file and sources it inside the container.
|
**Workaround:** The system extracts only authentication variables (`CLAUDE_CODE_OAUTH_TOKEN`, `ANTHROPIC_API_KEY`) from `.env` and mounts them for sourcing inside the container. Other env vars are not exposed.
|
||||||
|
|
||||||
To verify env vars are reaching the container:
|
To verify env vars are reaching the container:
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
2
SPEC.md
2
SPEC.md
@@ -230,7 +230,7 @@ The token can be extracted from `~/.claude/.credentials.json` if you're logged i
|
|||||||
ANTHROPIC_API_KEY=sk-ant-api03-...
|
ANTHROPIC_API_KEY=sk-ant-api03-...
|
||||||
```
|
```
|
||||||
|
|
||||||
The `.env` file is automatically mounted into the container at `/workspace/env-dir/env` and sourced by the entrypoint script. This workaround is needed because Apple Container loses `-e` environment variables when using `-i` (interactive mode with piped stdin).
|
Only the authentication variables (`CLAUDE_CODE_OAUTH_TOKEN` and `ANTHROPIC_API_KEY`) are extracted from `.env` and mounted into the container at `/workspace/env-dir/env`, then sourced by the entrypoint script. This ensures other environment variables in `.env` are not exposed to the agent. This workaround is needed because Apple Container loses `-e` environment variables when using `-i` (interactive mode with piped stdin).
|
||||||
|
|
||||||
### Changing the Assistant Name
|
### Changing the Assistant Name
|
||||||
|
|
||||||
|
|||||||
@@ -111,16 +111,29 @@ function buildVolumeMounts(group: RegisteredGroup, isMain: boolean): VolumeMount
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Environment file directory (workaround for Apple Container -i env var bug)
|
// Environment file directory (workaround for Apple Container -i env var bug)
|
||||||
|
// Only expose specific auth variables needed by Claude Code, not the entire .env
|
||||||
const envDir = path.join(DATA_DIR, 'env');
|
const envDir = path.join(DATA_DIR, 'env');
|
||||||
fs.mkdirSync(envDir, { recursive: true });
|
fs.mkdirSync(envDir, { recursive: true });
|
||||||
const envFile = path.join(projectRoot, '.env');
|
const envFile = path.join(projectRoot, '.env');
|
||||||
if (fs.existsSync(envFile)) {
|
if (fs.existsSync(envFile)) {
|
||||||
fs.copyFileSync(envFile, path.join(envDir, 'env'));
|
const envContent = fs.readFileSync(envFile, 'utf-8');
|
||||||
mounts.push({
|
const allowedVars = ['CLAUDE_CODE_OAUTH_TOKEN', 'ANTHROPIC_API_KEY'];
|
||||||
hostPath: envDir,
|
const filteredLines = envContent
|
||||||
containerPath: '/workspace/env-dir',
|
.split('\n')
|
||||||
readonly: true
|
.filter(line => {
|
||||||
});
|
const trimmed = line.trim();
|
||||||
|
if (!trimmed || trimmed.startsWith('#')) return false;
|
||||||
|
return allowedVars.some(v => trimmed.startsWith(`${v}=`));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (filteredLines.length > 0) {
|
||||||
|
fs.writeFileSync(path.join(envDir, 'env'), filteredLines.join('\n') + '\n');
|
||||||
|
mounts.push({
|
||||||
|
hostPath: envDir,
|
||||||
|
containerPath: '/workspace/env-dir',
|
||||||
|
readonly: true
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (group.containerConfig?.additionalMounts) {
|
if (group.containerConfig?.additionalMounts) {
|
||||||
|
|||||||
Reference in New Issue
Block a user