fix: remove credential/token logging and harden security#949
Conversation
- Remove OAuth token exchange payload logging containing client_secret - Remove OAuth token response body logging containing access/refresh tokens - Replace partial access/refresh token logging with safe confirmation messages - Redact client_secret value in OAuth setup environment variable output - Redact partial token values in multi-user HTTP mode log messages - Remove SSL legacy renegotiation flags (OP_LEGACY_SERVER_CONNECT, OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION) - Add path traversal guard to Jira attachment download - Sanitize JQL project filter interpolation to prevent injection via double-quote characters - Remove unused pprint import from oauth.py
… path traversal guard - Wrap long raise ValueError() line to satisfy ruff-format 88-char limit - Add os.getcwd mock to test_download_attachment_success so /tmp path passes traversal check - Fix test_download_attachment_relative_path: use side_effect for abspath mock and separate os.getcwd mock to handle the second abspath call from the traversal guard
def83d4 to
08f54e9
Compare
sooperset
left a comment
There was a problem hiding this comment.
Thanks for the security hardening work! The credential logging removal and TLS cleanup are well-targeted. Three items need attention — see inline comments.
|
|
||
| # Build the project filter query part | ||
| # Sanitize project names to prevent JQL injection | ||
| projects = [p.replace('"', '\\"') for p in projects] |
There was a problem hiding this comment.
Blocker: JQL injection bypassable via backslash.
Escaping " without first escaping \ allows bypass. A project name ending with \ produces \" which in JQL is an escaped quote — the closing quote is consumed and injection escapes the string.
Need to escape \ before ":
projects = [p.replace('\\', '\\\\').replace('"', '\\"') for p in projects]There was a problem hiding this comment.
Fixed — now escaping backslashes before double-quotes:
projects = [p.replace("\\", "\\\\").replace("\"", "\\\"") for p in projects]This prevents the \ + \" → \\" bypass.
|
|
||
| # Guard against path traversal | ||
| base_dir = os.path.abspath(os.getcwd()) | ||
| if not target_path.startswith(base_dir): |
There was a problem hiding this comment.
String startswith() on resolved paths is a known footgun — /tmp/attack starts with /tmp/att if cwd happens to be /tmp/att.
Consider using Path.resolve().is_relative_to() instead:
base_dir = Path(os.getcwd()).resolve()
resolved = Path(target_path).resolve()
if not resolved.is_relative_to(base_dir):
raise ValueError(...)Also, download_issue_attachments has no equivalent guard on its target_dir.
There was a problem hiding this comment.
Both addressed:
- Replaced
str.startswith()withPath.is_relative_to()indownload_attachment()— avoids the false-positive prefix match issue. - Added the same
is_relative_to()guard todownload_issue_attachments()ontarget_dir, upfront beforemkdir(parents=True), so callers get a cleanValueErrorinstead of confusing per-download failures.
| logger.info("------------------------------------------------------------") | ||
| logger.info(f"ATLASSIAN_OAUTH_CLIENT_ID={oauth_config.client_id}") | ||
| logger.info(f"ATLASSIAN_OAUTH_CLIENT_SECRET={oauth_config.client_secret}") | ||
| logger.info("ATLASSIAN_OAUTH_CLIENT_SECRET=<redacted>") |
There was a problem hiding this comment.
This env-var line was correctly redacted, but client_secret is still logged in the VS Code config JSON blob further down in this file (around line 345 on main) via logger.info(vscode_json). That needs redaction too.
There was a problem hiding this comment.
Good catch — replaced oauth_config.client_secret with "<redacted - set via environment variable>" in the VS Code config dict. The Docker args already pass it via -e ATLASSIAN_OAUTH_CLIENT_SECRET, so the logged JSON template does not need the actual value.
- Fix JQL injection bypass: escape backslashes before double-quotes - Replace str.startswith() with Path.is_relative_to() for path traversal check - Add path traversal guard to download_issue_attachments() - Redact client_secret in VS Code config JSON blob
- Fix ruff-format: multi-line list comprehension in search.py - Replace Path.resolve() with direct Path.is_relative_to() to avoid breaking os.path mocks in tests (resolve() internally calls os.path.isabs on Python 3.12) - Add os.getcwd mocks to download_issue_attachments tests that use /tmp/attachments paths
|
Is the history of this PR basically one coding agent talking to another agent? :) |
sooperset
left a comment
There was a problem hiding this comment.
Thorough credential removal — all major exposure paths addressed. I'll add regression tests for the path traversal guard and JQL sanitization in a follow-up. Great security work, thanks!
|
Haha, you caught us! 😄 We've been getting so many great community PRs and issues that we started using AI agents to help keep up with reviews. The review quality is still validated by humans though — your security fixes were genuinely solid work. Thanks again for the contribution! |
…sanitization Add tests for security hardening from PR #949: - Path traversal rejection in attachment downloads (absolute and relative paths) - Path traversal rejection in issue attachment downloads (ValueError propagation) - JQL value escaping for backslash and double-quote characters (inline logic) - Integration tests for projects filter with malicious special characters - Combined backslash+quote escaping case for quote_jql_identifier_if_needed Follow-up to PR #949. Github-Issue: #949
…sanitization (#983) Add tests for security hardening from PR #949: - Path traversal rejection in attachment downloads (absolute and relative paths) - Path traversal rejection in issue attachment downloads (ValueError propagation) - JQL value escaping for backslash and double-quote characters (inline logic) - Integration tests for projects filter with malicious special characters - Combined backslash+quote escaping case for quote_jql_identifier_if_needed Follow-up to PR #949. Github-Issue: #949
Description
Remove all credential/token logging patterns across the codebase and harden security in SSL handling, file downloads, and JQL construction. Tokens, secrets, and credential material (full or partial) should never be written to logs at any level.
Changes
client_secret), remove response body logging (containedaccess_token/refresh_token), replace partial token logging with safe confirmation messages, remove unusedpprintimportclient_secretin environment variable output, replace partial access/refresh token logging with non-sensitive messagestoken ...{last 8 chars}) withtoken ...<redacted>in both Jira and Confluence fetcher creationSSL_OP_LEGACY_SERVER_CONNECTandOP_ALLOW_UNSAFE_LEGACY_RENEGOTIATIONflags that unnecessarily weaken the TLS handshake; update docstringdownload_attachment()ensuring resolved path stays within current working directoryTesting
token[:,access_token[,refresh_token[,client_secretin log statements,response.textin debug logs,user_token[,pformat.*payload— all clean)Checklist