Feat/secure credentials#556
Conversation
Greptile SummaryAdds
Confidence Score: 5/5Safe to merge; the credential isolation mechanism is structurally sound and all previously identified blocking issues have been addressed. The security model is correctly implemented end-to-end: names-only in the system prompt, placeholder substitution at the outermost wrapper layer before any inner tool logic runs, and output scrubbing before results reach the LLM. Child agents correctly inherit the credentials dict through the shallow-copied context. The No files require special attention. Important Files Changed
Reviews (4): Last reviewed commit: "fix: remove orphaned duplicate loop caus..." | Re-trigger Greptile |
Adds --credentials KEY=VALUE[,...] and --credentials-file path.json CLI
flags so authorization secrets (usernames, passwords, API keys) can be
supplied to a scan without the LLM ever seeing the actual values.
How it works:
- Credential names are listed in the system prompt so the LLM knows
what is available.
- The LLM writes {{NAME}} placeholders in any tool input (shell commands,
HTTP bodies, file writes, etc.).
- Before the tool executes the framework substitutes the real value; after
execution, any credential values in the output are replaced with
[CREDENTIAL:NAME] before the LLM sees the result.
- The LLM therefore never handles the actual secret at any point in the
conversation history.
Changes:
- strix/interface/main.py: --credentials / --credentials-file flags with
full validation (_parse_credentials helper)
- strix/interface/cli.py, tui/app.py: forward credentials into scan_config
- strix/core/inputs.py: add credential_names to system prompt context;
skip parallel_tool_calls=False when routing via proxy to avoid a Bedrock
tool_choice.type error
- strix/core/runner.py: place credentials dict in runtime context so all
tool wrappers can read them via ctx.context["credentials"]
- strix/tools/credentials/tool.py: substitute_credentials() and
scrub_credentials() pure utilities
- strix/agents/factory.py: _wrap_credential_substitution() applied to
_BASE_TOOLS, exec_command, write_stdin, and filesystem tools; uses
dataclasses.replace for singleton FunctionTools, in-place mutation for
subclasses (e.g. ViewImageTool) that override __init__
- strix/agents/prompts/system_prompt.jinja: CREDENTIALS AVAILABLE block
explains {{NAME}} placeholder syntax using {% raw %} so Jinja does not
evaluate the braces as template expressions
- pyproject.toml: pytest dev dependency and ruff per-file ignores
- tests: 31 tests covering CLI parsing, scope context, substitution,
scrubbing, and wrapper integration
- docs: README, cli.mdx, instructions.mdx updated to document the new
flags and remove inline secret examples
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
affaf32 to
664d64a
Compare
Keys with hyphens or other special characters would silently fail substitution since _PLACEHOLDER_RE only matches word chars/digits/underscores. Now mirrors the validation already applied to --credentials inline keys. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
The pulled commit introduced an incomplete duplicate of the credentials file parsing loop (missing closing paren), preventing the module from compiling. Remove the orphaned fragment, keeping the complete block. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds --credentials KEY=VALUE[,...] and --credentials-file path.json CLI flags so authorization secrets (usernames, passwords, API keys) can be supplied to a scan without the LLM ever seeing the actual values.
How it works:
Changes: