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.
Files changed (42) hide show
  1. configwarden-0.3.0/.gitignore +53 -0
  2. configwarden-0.3.0/CHANGELOG.md +106 -0
  3. configwarden-0.3.0/LICENSE +201 -0
  4. configwarden-0.3.0/PKG-INFO +154 -0
  5. configwarden-0.3.0/README.md +131 -0
  6. configwarden-0.3.0/SECURITY.md +15 -0
  7. configwarden-0.3.0/docs/GUIDE-FR.md +170 -0
  8. configwarden-0.3.0/examples/safe-mcp/claude-settings.example.json +7 -0
  9. configwarden-0.3.0/examples/safe-mcp/mcp.json +30 -0
  10. configwarden-0.3.0/examples/safe-mcp/vscode.mcp.jsonc +10 -0
  11. configwarden-0.3.0/examples/vulnerable-mcp/claude-settings.example.json +7 -0
  12. configwarden-0.3.0/examples/vulnerable-mcp/mcp.json +36 -0
  13. configwarden-0.3.0/examples/vulnerable-mcp/vscode.mcp.jsonc +11 -0
  14. configwarden-0.3.0/pyproject.toml +94 -0
  15. configwarden-0.3.0/src/configwarden/__init__.py +3 -0
  16. configwarden-0.3.0/src/configwarden/__main__.py +5 -0
  17. configwarden-0.3.0/src/configwarden/cli.py +154 -0
  18. configwarden-0.3.0/src/configwarden/commands.py +849 -0
  19. configwarden-0.3.0/src/configwarden/config.py +72 -0
  20. configwarden-0.3.0/src/configwarden/jsonc.py +70 -0
  21. configwarden-0.3.0/src/configwarden/models.py +62 -0
  22. configwarden-0.3.0/src/configwarden/redact.py +191 -0
  23. configwarden-0.3.0/src/configwarden/reporters/__init__.py +9 -0
  24. configwarden-0.3.0/src/configwarden/reporters/json_reporter.py +19 -0
  25. configwarden-0.3.0/src/configwarden/reporters/sarif.py +109 -0
  26. configwarden-0.3.0/src/configwarden/reporters/text.py +45 -0
  27. configwarden-0.3.0/src/configwarden/rules/__init__.py +8 -0
  28. configwarden-0.3.0/src/configwarden/rules/mcp.py +1251 -0
  29. configwarden-0.3.0/src/configwarden/rules/secrets.py +107 -0
  30. configwarden-0.3.0/src/configwarden/scanner.py +176 -0
  31. configwarden-0.3.0/src/configwarden/values.py +102 -0
  32. configwarden-0.3.0/tests/__init__.py +0 -0
  33. configwarden-0.3.0/tests/conftest.py +32 -0
  34. configwarden-0.3.0/tests/test_auto_approve.py +169 -0
  35. configwarden-0.3.0/tests/test_config.py +43 -0
  36. configwarden-0.3.0/tests/test_hardening.py +521 -0
  37. configwarden-0.3.0/tests/test_mcp.py +244 -0
  38. configwarden-0.3.0/tests/test_real_configs.py +446 -0
  39. configwarden-0.3.0/tests/test_review_fixes.py +741 -0
  40. configwarden-0.3.0/tests/test_scanner_and_cli.py +81 -0
  41. configwarden-0.3.0/tests/test_secrets.py +57 -0
  42. 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
+ [![CI](https://github.com/Matadi-afk/configwarden/actions/workflows/ci.yml/badge.svg)](https://github.com/Matadi-afk/configwarden/actions/workflows/ci.yml)
29
+ ![License](https://img.shields.io/badge/license-Apache--2.0-blue)
30
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue)
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
+ [![CI](https://github.com/Matadi-afk/configwarden/actions/workflows/ci.yml/badge.svg)](https://github.com/Matadi-afk/configwarden/actions/workflows/ci.yml)
6
+ ![License](https://img.shields.io/badge/license-Apache--2.0-blue)
7
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue)
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