configwarden 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- configwarden-0.3.0/.gitignore +53 -0
- configwarden-0.3.0/CHANGELOG.md +106 -0
- configwarden-0.3.0/LICENSE +201 -0
- configwarden-0.3.0/PKG-INFO +154 -0
- configwarden-0.3.0/README.md +131 -0
- configwarden-0.3.0/SECURITY.md +15 -0
- configwarden-0.3.0/docs/GUIDE-FR.md +170 -0
- configwarden-0.3.0/examples/safe-mcp/claude-settings.example.json +7 -0
- configwarden-0.3.0/examples/safe-mcp/mcp.json +30 -0
- configwarden-0.3.0/examples/safe-mcp/vscode.mcp.jsonc +10 -0
- configwarden-0.3.0/examples/vulnerable-mcp/claude-settings.example.json +7 -0
- configwarden-0.3.0/examples/vulnerable-mcp/mcp.json +36 -0
- configwarden-0.3.0/examples/vulnerable-mcp/vscode.mcp.jsonc +11 -0
- configwarden-0.3.0/pyproject.toml +94 -0
- configwarden-0.3.0/src/configwarden/__init__.py +3 -0
- configwarden-0.3.0/src/configwarden/__main__.py +5 -0
- configwarden-0.3.0/src/configwarden/cli.py +154 -0
- configwarden-0.3.0/src/configwarden/commands.py +849 -0
- configwarden-0.3.0/src/configwarden/config.py +72 -0
- configwarden-0.3.0/src/configwarden/jsonc.py +70 -0
- configwarden-0.3.0/src/configwarden/models.py +62 -0
- configwarden-0.3.0/src/configwarden/redact.py +191 -0
- configwarden-0.3.0/src/configwarden/reporters/__init__.py +9 -0
- configwarden-0.3.0/src/configwarden/reporters/json_reporter.py +19 -0
- configwarden-0.3.0/src/configwarden/reporters/sarif.py +109 -0
- configwarden-0.3.0/src/configwarden/reporters/text.py +45 -0
- configwarden-0.3.0/src/configwarden/rules/__init__.py +8 -0
- configwarden-0.3.0/src/configwarden/rules/mcp.py +1251 -0
- configwarden-0.3.0/src/configwarden/rules/secrets.py +107 -0
- configwarden-0.3.0/src/configwarden/scanner.py +176 -0
- configwarden-0.3.0/src/configwarden/values.py +102 -0
- configwarden-0.3.0/tests/__init__.py +0 -0
- configwarden-0.3.0/tests/conftest.py +32 -0
- configwarden-0.3.0/tests/test_auto_approve.py +169 -0
- configwarden-0.3.0/tests/test_config.py +43 -0
- configwarden-0.3.0/tests/test_hardening.py +521 -0
- configwarden-0.3.0/tests/test_mcp.py +244 -0
- configwarden-0.3.0/tests/test_real_configs.py +446 -0
- configwarden-0.3.0/tests/test_review_fixes.py +741 -0
- configwarden-0.3.0/tests/test_scanner_and_cli.py +81 -0
- configwarden-0.3.0/tests/test_secrets.py +57 -0
- configwarden-0.3.0/tests/test_wrapped_commands.py +312 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# .gitignore : liste des fichiers que Git ne doit JAMAIS envoyer sur GitHub.
|
|
3
|
+
# Il doit exister AVANT le premier commit.
|
|
4
|
+
# =============================================================================
|
|
5
|
+
|
|
6
|
+
# --- 🔐 SECRETS : la section la plus importante --------------------------------
|
|
7
|
+
.env
|
|
8
|
+
.env.*
|
|
9
|
+
!.env.example
|
|
10
|
+
*.pem
|
|
11
|
+
*.key
|
|
12
|
+
*.p12
|
|
13
|
+
*.pfx
|
|
14
|
+
id_rsa*
|
|
15
|
+
id_ed25519*
|
|
16
|
+
# Fichiers de secrets courants (noms précis : un motif trop large comme
|
|
17
|
+
# « secrets.* » ignorerait aussi notre code source rules/secrets.py).
|
|
18
|
+
secrets.json
|
|
19
|
+
secrets.yaml
|
|
20
|
+
secrets.yml
|
|
21
|
+
secrets.toml
|
|
22
|
+
secrets.env
|
|
23
|
+
credentials.json
|
|
24
|
+
credentials.yaml
|
|
25
|
+
credentials.yml
|
|
26
|
+
*.secret
|
|
27
|
+
|
|
28
|
+
# --- Python ----------------------------------------------------------------------
|
|
29
|
+
__pycache__/
|
|
30
|
+
*.py[cod]
|
|
31
|
+
*.egg-info/
|
|
32
|
+
build/
|
|
33
|
+
dist/
|
|
34
|
+
.venv/
|
|
35
|
+
venv/
|
|
36
|
+
.pytest_cache/
|
|
37
|
+
.ruff_cache/
|
|
38
|
+
.coverage
|
|
39
|
+
htmlcov/
|
|
40
|
+
|
|
41
|
+
# --- Résultats de scan (peuvent contenir des chemins ou infos sensibles) --------
|
|
42
|
+
*.sarif
|
|
43
|
+
configwarden-report.*
|
|
44
|
+
|
|
45
|
+
# --- Systèmes et éditeurs ------------------------------------------------------
|
|
46
|
+
.DS_Store
|
|
47
|
+
Thumbs.db
|
|
48
|
+
.idea/
|
|
49
|
+
# On partage la config VS Code du projet, mais pas les réglages perso.
|
|
50
|
+
.vscode/*
|
|
51
|
+
!.vscode/settings.json
|
|
52
|
+
!.vscode/extensions.json
|
|
53
|
+
!.vscode/launch.json
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses [Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
## [0.3.0] - 2026-10-08
|
|
9
|
+
|
|
10
|
+
### Security
|
|
11
|
+
Detection gaps found by an independent review of this release before publication, then re-checked by a second pass. A configuration crafted to evade configwarden could start a shell or an unverified package without any finding. No user report, no known exploitation.
|
|
12
|
+
- **Other package launchers were not checked**: `pnpm dlx`, `yarn dlx`, `bun x`, `npm exec`, `uv tool run` and `pipx run` download and run a package exactly like `npx` or `uvx`, but CW101, CW102 and CW107 skipped them. `uv run`, `pnpm exec`, `yarn exec`, `poetry run`, `pipenv run`, `pdm run`, `hatch run` and `conda run` are now unwrapped, and packages added with `uv run --with` are checked by CW107.
|
|
13
|
+
- **`env -S "…"` hid the real command** (`env -S "bash -c …"` reported nothing). The string is now split and analysed.
|
|
14
|
+
- **Other ways into a shell**: `su -c`, `runuser`, `script -c`, `setsid`, `busybox sh`, `npx -c` / `pnpm dlx -c`, WSL without `-e` followed by `;` or `|`, and shell operators (`&&`, `;`, `$(…)`, backquotes) in a command line written in `command`.
|
|
15
|
+
- **Remote scripts**: `uv run https://…`, `deno run https://…` (CW107) and `deno run npm:…` / `jsr:…` without an exact version (CW102).
|
|
16
|
+
- **Quoted program names** (`cmd /c "npx" …`) were not recognised.
|
|
17
|
+
- **Misleading host in CW107 messages**: for `git+https://github.com/owner/repo.git@main` the message showed `main` as the host, and a crafted `https://evil.example/x@github.com/…` displayed `github.com` instead of the server that really serves the code. The host is now the one git and curl connect to, and it is hidden when the URL is ambiguous.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- **Renamed from `agentguard` to `configwarden`.** The old name is too close to existing projects on PyPI and in the MCP ecosystem (one of them, an MCP proxy, also installs an `agentguard` command). The command and the Python package are now `configwarden`, and rule IDs keep their numbers with a new prefix: `AG103` becomes `CW103`. Entries for earlier releases below keep the old names.
|
|
21
|
+
- CW101 is now titled "MCP server runs a shell script or inline code".
|
|
22
|
+
- Examples no longer point to a GitHub account that may exist (`not--a--real--user` cannot be a valid account name).
|
|
23
|
+
- CW101: `cmd /c` that starts a program given as separate words, without special characters (`& | < > ^ % !`), is no longer reported, since it is the documented way to start `npx` on Windows; the program it starts is analysed instead. A single command-line string or special characters are still reported.
|
|
24
|
+
- CW102 only accepts **exact** versions: `pkg@^1.0.0`, `pkg@~1.2`, `pkg@1`, `pkg@beta`, `pkg>=1.0` or `pkg==1.*` are now reported as unpinned.
|
|
25
|
+
- CW104 and CW106 also cover whole home directories (`/home/name`, `/Users/name`, `C:\Users\name`, `%USERPROFILE%`, `$env:USERPROFILE`), any drive root, `/root`, and credential folders (`.ssh`, `.aws`, `.gnupg`, `.kube`, `.docker`, `.azure`).
|
|
26
|
+
- CW103 no longer reports documentation placeholders (`<YOUR_API_KEY>`, `your-api-key-here`, `xxxx`) or references written as `%VAR%`, `$env:VAR` or `${{ secrets.NAME }}`.
|
|
27
|
+
- CW100 (unreadable MCP configuration) is now **medium**: some AI clients still start the servers they can read from a broken file, so an unreadable file may hide a server.
|
|
28
|
+
- **Far fewer false alarms**, measured on 3,099 MCP configuration examples published in npm and PyPI package documentation (CW103: 428 → 64 findings, CW001: 5 → 0):
|
|
29
|
+
- CW103 ignores more documentation placeholders (`sk-...`, `ghp_xxxx`, `{API_KEY}`, `your_key`, phrases in other languages, variable names written as values), settings whose name only contains a sensitive word (`MAX_TOKENS`, `OAUTH_PORT`, `TOKEN_URL`, `CLIENT_ID`, `SORT_KEY`, `TOKENIZER_MODEL`…), booleans, short numbers and words (except for passwords), and file paths (`GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json`).
|
|
30
|
+
- CW001 ignores documentation values: AWS `…EXAMPLE` keys, `sk-ant-xxxx…`, Slack tokens without digits (`xoxb-your-bot-token`) and private-key headers followed by `...` or by nothing.
|
|
31
|
+
- CW102 no longer reports a local path (`npx /path/to/server`, `uvx --from ./pkg`).
|
|
32
|
+
- `NODE_TLS_REJECT_UNAUTHORIZED=0` is no longer reported as a hardcoded secret (CW103) but as disabled TLS checks (CW110).
|
|
33
|
+
- The same finding is reported only once per server.
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
- **CW109 (high)**: AI client settings that approve everything without asking: Claude Code (`enableAllProjectMcpServers`, `permissions.defaultMode: bypassPermissions`, `skipDangerousModePermissionPrompt`), VS Code (`chat.tools.global.autoApprove` and its former name `chat.tools.autoApprove`), Zed (`agent.always_allow_tool_actions`, `agent.tool_permissions.default: allow`, `session.trust_all_worktrees`), Cursor (`mcpAllowlist` or CLI `permissions.allow` granting `*:*`) and Kiro (Autopilot). Committed to a repository, such a setting turns opening a booby-trapped project into automatic execution.
|
|
37
|
+
- **SARIF paths relative to the current folder** (the repository root in CI), marked with `uriBaseId: %SRCROOT%`, so GitHub links alerts to the right file when a sub-folder is scanned. No absolute path is ever written to a report.
|
|
38
|
+
- Demo files in `examples/` for CW109 and for a `cmd /c` command (JSON with comments), named so that no AI client loads them.
|
|
39
|
+
- **Real-world configuration files**: configwarden now reads every `.json` / `.jsonc` file and finds MCP servers wherever the main AI clients keep them: VS Code (`.vscode/mcp.json`, legacy `mcp.servers` in settings, `devcontainer.json`), Claude Code (`~/.claude.json`, user and per-project servers), Gemini CLI (`.gemini/settings.json`, extensions), Zed (`context_servers`, both command formats), Cline, Roo Code, Kiro, Amazon Q and GitHub Copilot CLI files. Other JSON files are only reported when they contain MCP servers.
|
|
40
|
+
- **JSON with comments and trailing commas** (JSONC), as written by VS Code, Zed or Cursor. It is read in linear time, positions and line numbers are preserved, and a comment can never hide a syntax error. Raw control characters inside strings are tolerated, as lenient client parsers do.
|
|
41
|
+
- **Configurations that cannot be audited are reported** (CW100) instead of being silently skipped, so a tolerant AI client cannot run a server configwarden never saw: oversized, binary-looking or symbolic-link configuration files and folders of AI clients (`.vscode/`, `.cursor/`, `.gemini/`, `.claude/`…), and broken JSON files that declare MCP servers.
|
|
42
|
+
- Files encoded in **UTF-16 or UTF-32** (with a byte-order mark), which VS Code opens, are now read by every rule, including secret detection, instead of being skipped as binary.
|
|
43
|
+
- CW105 also checks Gemini CLI's `httpUrl` key.
|
|
44
|
+
- **Wrapped commands are analysed**: `cmd /c`, `wsl`, `env`, `sudo`, `timeout`, `nice` and the script given to `bash -c` / `pwsh -Command` are unwrapped, so CW102, CW104, CW106 and CW107 check the program that really runs. Windows launchers such as `npx.cmd` are recognised.
|
|
45
|
+
- CW101 also detects `bash -lc` and grouped options, `env sh -c`, `wsl bash -c`, abbreviated PowerShell options (`-e`, `-ec`, `-Com`…) and **inline code** (`node -e`, `python -c`, `ruby -e`, `perl -e`, `php -r`, `deno eval`).
|
|
46
|
+
- CW107 also detects GitHub shorthands (`npx owner/repo`), scp-style git addresses (`git@host:owner/repo`), Python direct references (`name @ git+https://…`) and Mercurial/Subversion/Bazaar sources.
|
|
47
|
+
- CW103 also detects passwords inside URLs (`postgres://user:password@host`) whatever the variable name, and literal default values in `${VAR:-default}`.
|
|
48
|
+
- **CW110 (high)**: TLS certificate checks turned off (`NODE_TLS_REJECT_UNAUTHORIZED=0`, `PYTHONHTTPSVERIFY=0`, `*_SSL_VERIFY=false`, `*_INSECURE=true`, `GIT_SSL_NO_VERIFY`, `UV_INSECURE_HOST`, `--insecure`, `--strict-ssl=false`, `--allow-insecure-host`, `--insecure-skip-tls-verify`…): anyone on the network path could read or change the traffic, tokens included.
|
|
49
|
+
- CW103 also detects secrets **on the command line** (`--api-key …`, `--token=…`, `-e API_KEY=…`, `--header "Authorization: Bearer …"`), which other local users can also read in the process list, secrets **in URLs** (token as user name, `?api_key=…`, signed `sig=` parameters) in `url`, `env` and arguments, JSON-encoded headers in an environment variable, and `*_SESSION` / `*_COOKIE` keys.
|
|
50
|
+
- A whole command line written in `command` (`"npx -y pkg"`) is now analysed.
|
|
51
|
+
|
|
52
|
+
## [0.2.2] - 2026-10-07
|
|
53
|
+
|
|
54
|
+
### Security
|
|
55
|
+
Found by an independent review of 0.2.1, then re-checked by two further bypass attempts on the fixes. All issues require a scanned file or repository crafted by an attacker. No user report, no known exploitation.
|
|
56
|
+
- **Credentials still leaked in reports**: URLs with several `@`, a `/`, `?`, `#`, quote or space in the password, a token in the query string (`?token=…`) or in the path of a private registry, and npm shorthands such as `github:user:token@…` were not fully masked. AG107 now shows only the origin of the URL (`https://host/…`).
|
|
57
|
+
- **Crash on a malformed URL**: an invalid `url` (e.g. `http://[broken`) stopped the whole scan, and Python's error message could echo the password and raw escape codes. It is now reported as AG105 without echoing the URL, and an unexpected error in one server no longer hides the findings of the others.
|
|
58
|
+
- **Report crash on invalid Unicode**: a lone surrogate in a server name or file name made every output format fail and left an empty SARIF file. Surrogates and every Unicode default-ignorable character (zero-width, BOM, tag characters, variation selectors…), which can hide text from humans while an AI reading the report still sees it, are now escaped.
|
|
59
|
+
- **Report written through a symbolic link**: `--output` followed a symlink planted in the scanned repository (`agentguard.sarif -> ../file`, or a symlinked folder), which could overwrite another file in CI. agentguard now refuses to write through a symlink or to an output path containing `..`.
|
|
60
|
+
- **Denial of service**: line numbers were computed in quadratic time; a crafted file of a few hundred KB blocked the scan for minutes. A FIFO in the scanned tree blocked it forever. Both are fixed (single pass, regular files only).
|
|
61
|
+
|
|
62
|
+
### Changed
|
|
63
|
+
- Short secrets (under 16 characters) are fully masked (`****`) instead of showing their first 4 characters.
|
|
64
|
+
- AG103 no longer treats `PATH` as a secret (`PAT` must be a whole word) and now detects `*_PASS` keys.
|
|
65
|
+
- AG102/AG107 know which `npx` and `uvx` options take a value (`--registry`, `--index-url`, `uvx -p 3.12`…), which were mistaken for the package; `uvx --with git+…` is now flagged.
|
|
66
|
+
- Files starting with a UTF-8 BOM are now analysed instead of being reported as invalid JSON.
|
|
67
|
+
- Line numbers count only real line breaks (`\n`), as editors and GitHub do; SARIF URIs are percent-encoded.
|
|
68
|
+
- Unreadable folders are counted as skipped, and the text report says when some files could not be analysed.
|
|
69
|
+
|
|
70
|
+
## [0.2.1] - 2026-10-07
|
|
71
|
+
|
|
72
|
+
### Security
|
|
73
|
+
Three issues found during an internal security review of agentguard itself. They could only be triggered by a scanned file crafted by an attacker. No user report, no known exploitation.
|
|
74
|
+
- **Credentials leaked in reports**: AG107 and AG102 copied package URLs verbatim, so `git+https://user:token@host/…` printed the token in clear in text, JSON and SARIF output. Credentials embedded in URLs are now masked (`https://****@host/…`).
|
|
75
|
+
- **Output injection**: server names and file paths were printed as-is. Newlines could forge GitHub Actions workflow commands (lines starting with `::`) and ANSI or bidirectional control characters could hide or rewrite terminal output. All control, line-separator and bidi characters in findings are now escaped (`\n`, `\x1b`, `\u202e`…), whatever the output format.
|
|
76
|
+
- **Denial of service**: a deeply nested JSON file (`[[[[…]]]]`) crashed the whole scan with a `RecursionError`. It is now reported as AG100 (unreadable configuration) and the rest of the project is still scanned.
|
|
77
|
+
|
|
78
|
+
### Added
|
|
79
|
+
- `tests/test_hardening.py`: regression tests that replay each attack, plus a permanent check that no invisible or bidirectional characters exist in the project's own source code.
|
|
80
|
+
|
|
81
|
+
### Changed
|
|
82
|
+
- Development: pre-commit hooks are pinned to commit SHAs instead of tags.
|
|
83
|
+
|
|
84
|
+
## [0.2.0] - 2026-10-06
|
|
85
|
+
|
|
86
|
+
### Added
|
|
87
|
+
- **AG106** (high): container-based MCP servers (`docker`, `podman`, `nerdctl` `run`) that break isolation: `--privileged`, host namespaces (`--network host`, `--pid host`…), mounts of `/`, the home directory, `C:\`, `/etc`, `/root`, `/var/run` or the Docker socket, dangerous `--cap-add`, `--security-opt …=unconfined`.
|
|
88
|
+
- **AG107** (high): MCP packages installed from git or a URL (`github:`, `git+https://`, `https://…tgz`, `uvx --from git+…`) instead of the npm / PyPI registry.
|
|
89
|
+
- **AG108** (medium): tools that run without user confirmation (`alwaysAllow`, `autoApprove`, `trust: true`).
|
|
90
|
+
- Demo entries for the new rules in `examples/vulnerable-mcp` and their fixed versions in `examples/safe-mcp`.
|
|
91
|
+
|
|
92
|
+
### Changed
|
|
93
|
+
- AG102 (unpinned package) is no longer reported when AG107 already flags the same package, to avoid duplicate alerts.
|
|
94
|
+
|
|
95
|
+
## [0.1.0] - 2026-10-05
|
|
96
|
+
|
|
97
|
+
### Added
|
|
98
|
+
- First release: AG001 (hardcoded secrets) and AG100–AG105 (MCP configuration checks).
|
|
99
|
+
- Text, JSON and SARIF 2.1.0 reports; exit codes for CI.
|
|
100
|
+
- Zero runtime dependencies; secrets are always redacted in reports.
|
|
101
|
+
|
|
102
|
+
[Unreleased]: https://github.com/Matadi-afk/configwarden/compare/v0.3.0...HEAD
|
|
103
|
+
[0.3.0]: https://github.com/Matadi-afk/configwarden/compare/v0.2.2...v0.3.0
|
|
104
|
+
[0.2.2]: https://github.com/Matadi-afk/configwarden/compare/v0.2.1...v0.2.2
|
|
105
|
+
[0.2.1]: https://github.com/Matadi-afk/configwarden/compare/v0.2.0...v0.2.1
|
|
106
|
+
[0.2.0]: https://github.com/Matadi-afk/configwarden/releases/tag/v0.2.0
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: configwarden
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Security scanner for AI agent configurations (MCP servers, secrets, supply chain).
|
|
5
|
+
Project-URL: Homepage, https://github.com/Matadi-afk/configwarden
|
|
6
|
+
Project-URL: Issues, https://github.com/Matadi-afk/configwarden/issues
|
|
7
|
+
Author: configwarden contributors
|
|
8
|
+
License-Expression: Apache-2.0
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: ai-agents,devsecops,llm,mcp,sarif,secrets,security
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Topic :: Security
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: pip-audit>=2.9; extra == 'dev'
|
|
19
|
+
Requires-Dist: pre-commit>=4.0; extra == 'dev'
|
|
20
|
+
Requires-Dist: pytest>=9.0; extra == 'dev'
|
|
21
|
+
Requires-Dist: ruff>=0.16; extra == 'dev'
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# configwarden
|
|
25
|
+
|
|
26
|
+
**Security scanner for AI agent configurations.** Finds hardcoded secrets, dangerous MCP server setups and supply-chain risks before they reach production.
|
|
27
|
+
|
|
28
|
+
[](https://github.com/Matadi-afk/configwarden/actions/workflows/ci.yml)
|
|
29
|
+

|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
AI agents (Claude, Cursor, VS Code Copilot…) are increasingly wired to tools through the **Model Context Protocol (MCP)**. One bad config line can hand an agent, or anyone who hijacks it through prompt injection, a shell on your machine or your whole home directory. `configwarden` catches these mistakes in seconds.
|
|
33
|
+
|
|
34
|
+
- **Zero runtime dependencies**: nothing extra to trust.
|
|
35
|
+
- **Never prints a secret in full**: reports are safe to share in CI logs.
|
|
36
|
+
- **SARIF output**: results show up natively in GitHub Code Scanning and other security dashboards.
|
|
37
|
+
|
|
38
|
+
*Formerly named `agentguard`: renamed in October 2026 because that name was too close to other projects. Releases up to v0.2.2 use the old name.*
|
|
39
|
+
|
|
40
|
+
## Quick start
|
|
41
|
+
|
|
42
|
+
Requires Python 3.10+.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install configwarden==0.3.0
|
|
46
|
+
configwarden scan .
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Try it on the bundled example
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
git clone https://github.com/Matadi-afk/configwarden
|
|
53
|
+
cd configwarden
|
|
54
|
+
pip install .
|
|
55
|
+
configwarden scan examples/vulnerable-mcp # 14 findings
|
|
56
|
+
configwarden scan examples/safe-mcp # the fixed version: no issues
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
[HIGH] CW101 MCP server runs a shell script or inline code
|
|
61
|
+
mcp.json:16 Server 'helper' executes commands through 'bash -c'.
|
|
62
|
+
Fix: Call the server program directly, with its arguments as separate items ...
|
|
63
|
+
|
|
64
|
+
[HIGH] CW106 MCP server container escapes isolation
|
|
65
|
+
mcp.json:26 Server 'sandbox' runs a container with a mount of '/var/run/docker.sock'.
|
|
66
|
+
Fix: Remove --privileged, host namespaces and mounts of '/', the home directory or the Docker socket. ...
|
|
67
|
+
|
|
68
|
+
Scanned 3 file(s), skipped 0. 14 finding(s): 0 critical, 12 high, 2 medium, 0 low.
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Every value in `examples/` is a fake placeholder, and the example files are named so that no AI client loads them.
|
|
72
|
+
|
|
73
|
+
## Rules
|
|
74
|
+
|
|
75
|
+
| ID | Severity | What it detects |
|
|
76
|
+
|----|----------|-----------------|
|
|
77
|
+
| CW001 | critical | API keys and tokens written in clear (Anthropic, OpenAI, GitHub, AWS, Google, Hugging Face, Slack, Stripe, private keys); documentation examples (`…EXAMPLE`, `sk-xxxx`, truncated keys) are ignored |
|
|
78
|
+
| CW100 | medium | MCP config that cannot be parsed (some clients still run the servers they can read from a broken file) |
|
|
79
|
+
| CW101 | high | Shell running a script (`bash -c`, `pwsh -Command`, `su -c`), `cmd /c` or WSL with a command line or special characters, `npx -c`, a command line with shell operators in `command`, inline code (`node -e`, `python -c`) |
|
|
80
|
+
| CW102 | medium | Registry package without an exact version (`^1.0`, `@beta`, `>=1` are not pinned), whatever the launcher: `npx`, `uvx`, `pnpm dlx`, `yarn dlx`, `bun x`, `npm exec`, `uv tool run`, `pipx run`, `deno run npm:` |
|
|
81
|
+
| CW103 | high | Secret written literally in an MCP server's `env`, `headers`, command line (`--api-key …`, `-e TOKEN=…`) or URL (password, `?token=…`); placeholders, references and plain settings are ignored |
|
|
82
|
+
| CW104 | high | Filesystem server exposed to `/`, a whole drive or a whole home directory |
|
|
83
|
+
| CW105 | high | Remote MCP server reached over plain `http://` |
|
|
84
|
+
| CW106 | high | Docker/Podman server with `--privileged`, host namespaces, or mounts of `/`, the home directory, `.ssh`/`.aws`… or the Docker socket |
|
|
85
|
+
| CW107 | high | Package or script installed from git, a URL or a GitHub shorthand instead of the npm / PyPI registry (`uv run --with git+…`, `deno run https://…`…) |
|
|
86
|
+
| CW108 | medium | Tools auto-approved (`alwaysAllow`, `autoApprove`, `trust: true`): no human confirmation |
|
|
87
|
+
| CW109 | high | AI client set to approve everything: Claude Code `enableAllProjectMcpServers` or `bypassPermissions`, VS Code `chat.tools.global.autoApprove`, Zed, Cursor `*:*`, Kiro Autopilot |
|
|
88
|
+
| CW110 | high | TLS certificate checks turned off: `NODE_TLS_REJECT_UNAUTHORIZED=0`, `*_SSL_VERIFY=false`, `--insecure`, `--strict-ssl=false`, `--allow-insecure-host` |
|
|
89
|
+
|
|
90
|
+
Run `configwarden rules` to list them from the CLI.
|
|
91
|
+
|
|
92
|
+
## Supported configuration files
|
|
93
|
+
|
|
94
|
+
configwarden reads every `.json` / `.jsonc` file (comments and trailing commas allowed) and looks for MCP servers wherever each AI client keeps them:
|
|
95
|
+
|
|
96
|
+
| Client | Where the servers live |
|
|
97
|
+
|---|---|
|
|
98
|
+
| Claude Desktop, Cursor, Windsurf, Cline, Roo Code, Kiro, Amazon Q, GitHub Copilot CLI | `mcpServers` |
|
|
99
|
+
| Claude Code | `.mcp.json`, and `~/.claude.json` (user and per-project servers) |
|
|
100
|
+
| Gemini CLI | `mcpServers` in `.gemini/settings.json` and extensions (`url`, `httpUrl`) |
|
|
101
|
+
| VS Code | `servers` in `.vscode/mcp.json`, `mcp.servers` in settings, `devcontainer.json` customizations |
|
|
102
|
+
| Zed | `context_servers` in `settings.json` |
|
|
103
|
+
|
|
104
|
+
Other JSON files are only reported when they contain MCP servers. YAML (Continue) and TOML (Codex CLI) configurations are not supported yet.
|
|
105
|
+
|
|
106
|
+
Wrapped commands are unwrapped before being checked: `cmd /c npx …`, `wsl …`, `env VAR=1 …` (and `env -S`), `sudo …`, `uv run …`, `pnpm exec …` and `bash -c "…"` are all analysed for the program they really start.
|
|
107
|
+
|
|
108
|
+
## Usage
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
configwarden scan PATH [--format text|json|sarif] [--output FILE]
|
|
112
|
+
[--fail-on low|medium|high|critical] [--exclude GLOB]...
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Exit codes: `0` nothing at or above `--fail-on`, `1` findings, `2` usage error.
|
|
116
|
+
|
|
117
|
+
### GitHub Actions
|
|
118
|
+
|
|
119
|
+
```yaml
|
|
120
|
+
jobs:
|
|
121
|
+
configwarden:
|
|
122
|
+
runs-on: ubuntu-latest
|
|
123
|
+
permissions:
|
|
124
|
+
contents: read
|
|
125
|
+
security-events: write # needed to upload SARIF results
|
|
126
|
+
steps:
|
|
127
|
+
- uses: actions/checkout@v4 # pin actions to a commit SHA in production
|
|
128
|
+
- uses: actions/setup-python@v5
|
|
129
|
+
with:
|
|
130
|
+
python-version: "3.13"
|
|
131
|
+
- run: pip install configwarden==0.3.0
|
|
132
|
+
- run: configwarden scan . --format sarif --output configwarden.sarif
|
|
133
|
+
- uses: github/codeql-action/upload-sarif@v4
|
|
134
|
+
if: always()
|
|
135
|
+
with:
|
|
136
|
+
sarif_file: configwarden.sarif
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Results then appear in the repository's **Security → Code scanning** tab.
|
|
140
|
+
|
|
141
|
+
## Development
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
145
|
+
pip install -e ".[dev]"
|
|
146
|
+
pre-commit install
|
|
147
|
+
pytest
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
See [CHANGELOG.md](CHANGELOG.md) for release notes and [SECURITY.md](SECURITY.md) to report a vulnerability.
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
Apache-2.0
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# configwarden
|
|
2
|
+
|
|
3
|
+
**Security scanner for AI agent configurations.** Finds hardcoded secrets, dangerous MCP server setups and supply-chain risks before they reach production.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/Matadi-afk/configwarden/actions/workflows/ci.yml)
|
|
6
|
+

|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
AI agents (Claude, Cursor, VS Code Copilot…) are increasingly wired to tools through the **Model Context Protocol (MCP)**. One bad config line can hand an agent, or anyone who hijacks it through prompt injection, a shell on your machine or your whole home directory. `configwarden` catches these mistakes in seconds.
|
|
10
|
+
|
|
11
|
+
- **Zero runtime dependencies**: nothing extra to trust.
|
|
12
|
+
- **Never prints a secret in full**: reports are safe to share in CI logs.
|
|
13
|
+
- **SARIF output**: results show up natively in GitHub Code Scanning and other security dashboards.
|
|
14
|
+
|
|
15
|
+
*Formerly named `agentguard`: renamed in October 2026 because that name was too close to other projects. Releases up to v0.2.2 use the old name.*
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
Requires Python 3.10+.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install configwarden==0.3.0
|
|
23
|
+
configwarden scan .
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Try it on the bundled example
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
git clone https://github.com/Matadi-afk/configwarden
|
|
30
|
+
cd configwarden
|
|
31
|
+
pip install .
|
|
32
|
+
configwarden scan examples/vulnerable-mcp # 14 findings
|
|
33
|
+
configwarden scan examples/safe-mcp # the fixed version: no issues
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
[HIGH] CW101 MCP server runs a shell script or inline code
|
|
38
|
+
mcp.json:16 Server 'helper' executes commands through 'bash -c'.
|
|
39
|
+
Fix: Call the server program directly, with its arguments as separate items ...
|
|
40
|
+
|
|
41
|
+
[HIGH] CW106 MCP server container escapes isolation
|
|
42
|
+
mcp.json:26 Server 'sandbox' runs a container with a mount of '/var/run/docker.sock'.
|
|
43
|
+
Fix: Remove --privileged, host namespaces and mounts of '/', the home directory or the Docker socket. ...
|
|
44
|
+
|
|
45
|
+
Scanned 3 file(s), skipped 0. 14 finding(s): 0 critical, 12 high, 2 medium, 0 low.
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Every value in `examples/` is a fake placeholder, and the example files are named so that no AI client loads them.
|
|
49
|
+
|
|
50
|
+
## Rules
|
|
51
|
+
|
|
52
|
+
| ID | Severity | What it detects |
|
|
53
|
+
|----|----------|-----------------|
|
|
54
|
+
| CW001 | critical | API keys and tokens written in clear (Anthropic, OpenAI, GitHub, AWS, Google, Hugging Face, Slack, Stripe, private keys); documentation examples (`…EXAMPLE`, `sk-xxxx`, truncated keys) are ignored |
|
|
55
|
+
| CW100 | medium | MCP config that cannot be parsed (some clients still run the servers they can read from a broken file) |
|
|
56
|
+
| CW101 | high | Shell running a script (`bash -c`, `pwsh -Command`, `su -c`), `cmd /c` or WSL with a command line or special characters, `npx -c`, a command line with shell operators in `command`, inline code (`node -e`, `python -c`) |
|
|
57
|
+
| CW102 | medium | Registry package without an exact version (`^1.0`, `@beta`, `>=1` are not pinned), whatever the launcher: `npx`, `uvx`, `pnpm dlx`, `yarn dlx`, `bun x`, `npm exec`, `uv tool run`, `pipx run`, `deno run npm:` |
|
|
58
|
+
| CW103 | high | Secret written literally in an MCP server's `env`, `headers`, command line (`--api-key …`, `-e TOKEN=…`) or URL (password, `?token=…`); placeholders, references and plain settings are ignored |
|
|
59
|
+
| CW104 | high | Filesystem server exposed to `/`, a whole drive or a whole home directory |
|
|
60
|
+
| CW105 | high | Remote MCP server reached over plain `http://` |
|
|
61
|
+
| CW106 | high | Docker/Podman server with `--privileged`, host namespaces, or mounts of `/`, the home directory, `.ssh`/`.aws`… or the Docker socket |
|
|
62
|
+
| CW107 | high | Package or script installed from git, a URL or a GitHub shorthand instead of the npm / PyPI registry (`uv run --with git+…`, `deno run https://…`…) |
|
|
63
|
+
| CW108 | medium | Tools auto-approved (`alwaysAllow`, `autoApprove`, `trust: true`): no human confirmation |
|
|
64
|
+
| CW109 | high | AI client set to approve everything: Claude Code `enableAllProjectMcpServers` or `bypassPermissions`, VS Code `chat.tools.global.autoApprove`, Zed, Cursor `*:*`, Kiro Autopilot |
|
|
65
|
+
| CW110 | high | TLS certificate checks turned off: `NODE_TLS_REJECT_UNAUTHORIZED=0`, `*_SSL_VERIFY=false`, `--insecure`, `--strict-ssl=false`, `--allow-insecure-host` |
|
|
66
|
+
|
|
67
|
+
Run `configwarden rules` to list them from the CLI.
|
|
68
|
+
|
|
69
|
+
## Supported configuration files
|
|
70
|
+
|
|
71
|
+
configwarden reads every `.json` / `.jsonc` file (comments and trailing commas allowed) and looks for MCP servers wherever each AI client keeps them:
|
|
72
|
+
|
|
73
|
+
| Client | Where the servers live |
|
|
74
|
+
|---|---|
|
|
75
|
+
| Claude Desktop, Cursor, Windsurf, Cline, Roo Code, Kiro, Amazon Q, GitHub Copilot CLI | `mcpServers` |
|
|
76
|
+
| Claude Code | `.mcp.json`, and `~/.claude.json` (user and per-project servers) |
|
|
77
|
+
| Gemini CLI | `mcpServers` in `.gemini/settings.json` and extensions (`url`, `httpUrl`) |
|
|
78
|
+
| VS Code | `servers` in `.vscode/mcp.json`, `mcp.servers` in settings, `devcontainer.json` customizations |
|
|
79
|
+
| Zed | `context_servers` in `settings.json` |
|
|
80
|
+
|
|
81
|
+
Other JSON files are only reported when they contain MCP servers. YAML (Continue) and TOML (Codex CLI) configurations are not supported yet.
|
|
82
|
+
|
|
83
|
+
Wrapped commands are unwrapped before being checked: `cmd /c npx …`, `wsl …`, `env VAR=1 …` (and `env -S`), `sudo …`, `uv run …`, `pnpm exec …` and `bash -c "…"` are all analysed for the program they really start.
|
|
84
|
+
|
|
85
|
+
## Usage
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
configwarden scan PATH [--format text|json|sarif] [--output FILE]
|
|
89
|
+
[--fail-on low|medium|high|critical] [--exclude GLOB]...
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Exit codes: `0` nothing at or above `--fail-on`, `1` findings, `2` usage error.
|
|
93
|
+
|
|
94
|
+
### GitHub Actions
|
|
95
|
+
|
|
96
|
+
```yaml
|
|
97
|
+
jobs:
|
|
98
|
+
configwarden:
|
|
99
|
+
runs-on: ubuntu-latest
|
|
100
|
+
permissions:
|
|
101
|
+
contents: read
|
|
102
|
+
security-events: write # needed to upload SARIF results
|
|
103
|
+
steps:
|
|
104
|
+
- uses: actions/checkout@v4 # pin actions to a commit SHA in production
|
|
105
|
+
- uses: actions/setup-python@v5
|
|
106
|
+
with:
|
|
107
|
+
python-version: "3.13"
|
|
108
|
+
- run: pip install configwarden==0.3.0
|
|
109
|
+
- run: configwarden scan . --format sarif --output configwarden.sarif
|
|
110
|
+
- uses: github/codeql-action/upload-sarif@v4
|
|
111
|
+
if: always()
|
|
112
|
+
with:
|
|
113
|
+
sarif_file: configwarden.sarif
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Results then appear in the repository's **Security → Code scanning** tab.
|
|
117
|
+
|
|
118
|
+
## Development
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
122
|
+
pip install -e ".[dev]"
|
|
123
|
+
pre-commit install
|
|
124
|
+
pytest
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
See [CHANGELOG.md](CHANGELOG.md) for release notes and [SECURITY.md](SECURITY.md) to report a vulnerability.
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
Apache-2.0
|