Add continuous autonomous security testing framework (v3.0)#35
Add continuous autonomous security testing framework (v3.0)#35devatsecure merged 3 commits intomainfrom
Conversation
Maps Argus's current capabilities against the emerging continuous autonomous pentesting model (diff-aware scanning, AutoFix→PR→Retest loops, persistent knowledge base, agent-driven attack chaining, deployment-triggered scanning, code-to-runtime context). Includes concrete implementation paths and priority ordering for each gap. https://claude.ai/code/session_017NQsm2eBxfioLrad1C7keZ
Implements continuous autonomous security testing capabilities: - diff_impact_analyzer: Diff-intelligent scanner scoping with blast radius expansion via reverse dependency lookup - agent_chain_discovery: LLM-powered multi-step attack chain discovery with cross-component vulnerability analysis - autofix_pr_generator: AutoFix PR generation with closed-loop find→fix→verify orchestration - findings_store: SQLite-backed persistent findings with regression detection, MTTF, and historical context for LLM prompts - app_context_builder: Auto-detects framework, language, auth, cloud provider, IaC, middleware, and entry points for context-aware scanning - sast_dast_validator: SAST-to-DAST live validation with safety guards against production targets - GitHub Actions workflows for post-deploy scanning and automated retest Adds 13 config keys, integrates all modules into hybrid_analyzer.py pipeline, and includes 36 passing tests. https://claude.ai/code/session_017NQsm2eBxfioLrad1C7keZ
- README: Add v3.0 continuous security testing feature table, env vars, deployment-triggered scanning section, and guide doc link - CLAUDE.md: Add v3.0 summary, 6 new key files, and guide reference - CHANGELOG: Add v6.0.0 release notes with all 7 new modules, workflows, config keys, and 36 tests https://claude.ai/code/session_017NQsm2eBxfioLrad1C7keZ
✅ Hybrid Security Scan ResultsStatus: No critical or high severity issues 📊 Findings Summary
🛠️ Tools Used
📈 Metrics
🔗 LinksPowered by Argus Hybrid Analyzer |
| run: | | ||
| BRANCH="${{ github.event.pull_request.head.ref }}" | ||
| # Extract vuln type and finding ID from branch name: argus/fix-{type}-{id} | ||
| VULN_TYPE=$(echo "$BRANCH" | sed 's|argus/fix-||' | sed 's|-[a-f0-9]*$||') | ||
| FINDING_ID=$(echo "$BRANCH" | grep -oP '[a-f0-9]{8}$' || echo "unknown") | ||
| echo "vuln_type=$VULN_TYPE" >> $GITHUB_OUTPUT | ||
| echo "finding_id=$FINDING_ID" >> $GITHUB_OUTPUT | ||
| # Get changed files from the PR | ||
| CHANGED_FILES=$(gh pr view ${{ github.event.pull_request.number }} --json files -q '.files[].path' || echo "") | ||
| echo "changed_files=$CHANGED_FILES" >> $GITHUB_OUTPUT |
Check failure
Code scanning / Semgrep OSS
Semgrep Finding: yaml.github-actions.security.run-shell-injection.run-shell-injection Error
| script: | | ||
| const regression = '${{ steps.regression.outcome }}'; | ||
| const rescan = '${{ steps.rescan.outcome }}'; | ||
| const allPassed = regression === 'success' && rescan === 'success'; | ||
|
|
||
| const body = `## Argus Retest Results | ||
|
|
||
| | Check | Status | | ||
| |-------|--------| | ||
| | Regression Tests | ${regression === 'success' ? 'Passed' : 'Failed'} | | ||
| | SAST Rescan | ${rescan === 'success' ? 'Clean' : 'Issues found'} | | ||
| | **Overall** | **${allPassed ? 'Fix Verified' : 'Needs Review'}** | | ||
|
|
||
| ${allPassed ? 'The fix has been verified. The vulnerability is confirmed resolved.' : 'The retest found issues. Please review the scan results.'} | ||
|
|
||
| --- | ||
| *Argus Security Retest — triggered by merge of \`${{ github.event.pull_request.head.ref }}\`*`; | ||
|
|
||
| // Comment on the merged PR | ||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: ${{ github.event.pull_request.number }}, | ||
| body: body | ||
| }); |
Check failure
Code scanning / Semgrep OSS
Semgrep Finding: yaml.github-actions.security.github-script-injection.github-script-injection Error
| run: | | ||
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | ||
| echo "target_url=${{ inputs.target_url }}" >> $GITHUB_OUTPUT | ||
| echo "environment=${{ inputs.environment }}" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "target_url=${{ github.event.deployment.payload.web_url || '' }}" >> $GITHUB_OUTPUT | ||
| echo "environment=${{ github.event.deployment.environment }}" >> $GITHUB_OUTPUT | ||
| fi | ||
| # Get diff since last successful scan | ||
| PREV_SHA=$(git log --format='%H' -2 | tail -1) | ||
| echo "prev_sha=$PREV_SHA" >> $GITHUB_OUTPUT | ||
| CHANGED=$(git diff --name-only $PREV_SHA HEAD | head -100) | ||
| echo "has_changes=$( [ -n "$CHANGED" ] && echo true || echo false )" >> $GITHUB_OUTPUT | ||
|
|
Check failure
Code scanning / Semgrep OSS
Semgrep Finding: yaml.github-actions.security.run-shell-injection.run-shell-injection Error
| response = urllib.request.urlopen( | ||
| request, | ||
| timeout=self.timeout, | ||
| context=ctx, | ||
| ) |
Check warning
Code scanning / Semgrep OSS
Semgrep Finding: python.lang.security.audit.dynamic-urllib-use-detected.dynamic-urllib-use-detected Warning
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 4 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| max_duration=600, | ||
| ) | ||
| orch = DASTOrchestrator(config=config) | ||
| results = orch.run('${{ steps.context.outputs.target_url }}') |
There was a problem hiding this comment.
Script injection via target URL in workflow
High Severity
The ${{ steps.context.outputs.target_url }} is interpolated directly into an inline Python string on line 86. If the URL contains a single quote (e.g., from workflow_dispatch user input or a crafted deployment payload), it breaks out of the Python string literal, enabling arbitrary code execution in the workflow runner. This value originates from ${{ inputs.target_url }} which is directly user-controlled.
Additional Locations (1)
| - name: Extract fix metadata | ||
| id: meta | ||
| run: | | ||
| BRANCH="${{ github.event.pull_request.head.ref }}" |
There was a problem hiding this comment.
Shell injection via branch ref in workflow
High Severity
${{ github.event.pull_request.head.ref }} is interpolated directly into a shell script. While the if condition ensures the branch starts with argus/fix-, the remainder is attacker-controlled. A branch name containing shell metacharacters like $(cmd) or backticks would execute arbitrary commands during the run step, potentially exfiltrating secrets like ANTHROPIC_API_KEY or GITHUB_TOKEN.
|
|
||
| def __init__(self, db_path: str = ".argus/findings.db") -> None: | ||
| self.db_path = db_path | ||
| self._lock = threading.Lock() |
There was a problem hiding this comment.
Lock advertised as reentrant but uses non-reentrant Lock
Low Severity
The module docstring (line 16) states "Thread-safe write operations with a reentrant lock" but the implementation uses threading.Lock(), which is non-reentrant. If any future code path (or subclass) attempts to re-acquire the lock from within a locked section, it will deadlock. The type needs to match the documented contract — either use threading.RLock() or correct the docstring.
| row = cur.fetchone() | ||
| if row is None: | ||
| return False | ||
| return row["status"] == "fixed" |
There was a problem hiding this comment.
Regression detection returns stale result after record_scan
Medium Severity
is_regression checks whether the finding's current status equals "fixed". But record_scan resets regressions' status to "open" immediately upon detection. So get_historical_context calling is_regression after record_scan will always return False for regressions, since their status was already flipped to "open". The method needs to check fix_history records rather than relying on transient status.
Additional Locations (1)
…eview
- Sanitize ${{ }} expression interpolation in post-deploy-scan.yml and
argus-retest.yml by passing attacker-controlled values through env vars
instead of direct shell/script interpolation (HIGH severity)
- Fix is_regression() returning stale results by checking fix_history
records instead of transient status field (MEDIUM)
- Change threading.Lock() to threading.RLock() to match docstring (LOW)
https://claude.ai/code/session_017NQsm2eBxfioLrad1C7keZ


Description
This PR introduces a comprehensive continuous autonomous security testing framework that closes the gap between periodic security validation and every-deploy security coverage. It adds five new core modules and supporting infrastructure to enable diff-aware scanning, automated fix generation with PR creation, persistent findings tracking, and LLM-powered vulnerability chain discovery.
Type of Change
Changes Made
Core Modules Added
scripts/diff_impact_analyzer.py— Diff-intelligent scanner scopingDiffClassifier: Classifies changed files as security-relevant or skippable using pattern matchingDiffImpactAnalyzer: Expands changed files to their security blast radius via reverse dependency lookupDiffScopeBuilder: Combines classification and impact analysis into scanner-ready scopes with Semgrep CLI helpersscripts/autofix_pr_generator.py— Automated PR generation from remediation suggestionsAutoFixPRGenerator: Creates git branches, applies code fixes (diff or full-file replacement), commits with descriptive messagesClosedLoopOrchestrator: Orchestrates find → fix → verify → PR cycle with confidence-based filteringFixBranch,FixPR,LoopResult: Dataclasses for structured results and JSON serializationscripts/findings_store.py— Persistent SQLite-backed findings databasescripts/app_context_builder.py— Unified application context modelscripts/agent_chain_discovery.py— LLM-powered vulnerability chain discoveryVulnerabilityChainerwith AI-driven multi-step attack reasoningAgentChainDiscovery: Uses LLM to discover novel attack paths beyond static rulesCrossComponentAnalyzer: Identifies inter-module vulnerability combinationsAttackChain,CrossComponentRisk: Structured dataclasses for chain resultsSupporting Infrastructure
scripts/sast_dast_validator.py— SAST-to-DAST validation bridgeGitHub Actions Workflows:
.github/workflows/argus-retest.yml: Automatically retests after fix PRs are merged.github/workflows/post-deploy-scan.yml: Triggers security validation on deployment successConfiguration: Extended
scripts/config_loader.pywith toggles for all v3.0 featuresenable_diff_scoping,enable_findings_store,enable_app_context,enable_agent_chain_discovery, etc.Documentation:
docs/CONTINUOUS_SECURITY_TESTING_GUIDE.md: Comprehensive guide mapping current capabilities, gaps, and implementation pathsREADME.md, `CHANGELOG.https://claude.ai/code/session_017NQsm2eBxfioLrad1C7keZ
Note
Cursor Bugbot is generating a summary for commit c235c1e. Configure here.