Skip to content

Conversation

@JacobMagesHaskinsContrast
Copy link
Collaborator

Summary

Implements comprehensive command allowlist validation to prevent arbitrary command execution in GitHub Actions workflows. This security feature validates all BUILD_COMMAND and FORMATTING_COMMAND configuration values before execution.

Changes

Core Implementation

  • Command Validator Module (src/smartfix/config/command_validator.py)

    • ALLOWED_COMMANDS constant with comprehensive allowlist (Java, .NET, Python, Node.js, PHP, build tools, shell utilities)
    • BLOCKED_PATTERNS regex list for dangerous operations
    • validate_command() - Main validation orchestration
    • validate_shell_command() - Shell script execution validation (sh/bash only for .sh files)
    • validate_redirect() - File redirect validation (relative paths only)
    • contains_dangerous_patterns() - Dangerous pattern detection
    • split_command_chain() - Command parsing by operators
    • parse_command_segment() - Executable and argument extraction
    • extract_redirects() - Redirect path extraction
    • CommandValidationError exception class
  • Config Integration (src/config.py)

    • _validate_command() method added to Config class
    • Validation called for BUILD_COMMAND and FORMATTING_COMMAND in init
    • CommandValidationError converted to ConfigurationError
    • Follows existing validation patterns

Testing

  • Comprehensive Test Suite (test/test_command_validation.py)

    • 41 command validation tests covering all scenarios
    • TestAllowedCommands: Java, .NET, Python, Node.js, PHP, build tools
    • TestCommandChaining: &&, ||, ;, | operators
    • TestShellScriptValidation: sh/bash restrictions
    • TestRedirectValidation: relative path enforcement
    • TestDangerousPatterns: command substitution, eval, exec, rm -rf
    • TestBlockedCommands: disallowed executables
    • TestEdgeCases: empty commands, whitespace, special characters
    • TestErrorMessages: clear, actionable error messages
  • Full Test Suite: 369 passing tests

Documentation

  • README.md: Comprehensive security section with:

    • Command allowlist organized by language/ecosystem
    • Allowed operators documentation
    • File redirect restrictions
    • Shell command restrictions
    • Blocked patterns reference
    • Valid and invalid command examples
    • Error message documentation
    • Troubleshooting guide
  • security.md: Security features section referencing command allowlist

Security Features

Allowlist of approved executables - Only standard build, test, and format tools allowed
Dangerous pattern detection - Blocks command substitution, eval, exec, rm -rf, piping to shell
Shell command restrictions - sh/bash can only execute .sh files, -c flag blocked
File redirect validation - Relative paths only, blocks absolute paths and traversal
Operator validation - Only safe command chaining operators (&&, ||, ;, |)

Testing

  • ✅ All 369 unit tests passing
  • ✅ 41 new tests for command validation
  • ✅ Validation tested for all language ecosystems
  • ✅ Error messages verified for clarity
  • ✅ Edge cases covered

Breaking Changes

None. This is a security enhancement that validates existing configuration values.

Related

  • Jira: AIML-337
  • Beads completed: gad, 8re, q9y, wuv

🤖 Generated with Claude Code

Jacob Mages-Haskins and others added 10 commits December 23, 2025 09:56
- Created comprehensive design for command allowlist validation
- Defined allowlist for Java, .NET, Python, PHP, NodeJS build/format commands
- Designed moderate strictness validation with safe operators and redirects
- Created 4 beads with proper dependency structure
- Documented learnings and architectural decisions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Created src/smartfix/config/command_validator.py with comprehensive allowlist
- Implemented validation for build/format commands with security controls
- Added support for shell utilities (grep, sed, awk, cat, tee)
- Implemented bash line continuation handling (\\ newline processing)
- Created comprehensive unittest test suite (41 tests, all passing)
- Converted pytest tests to unittest for project consistency
- Updated src/smartfix/config/__init__.py to export validation functions
- Added .bv/ directory to .gitignore for beads viewer caches
- Added .gitattributes for beads merge strategy configuration

Security features implemented:
- Allowlist validation for executables
- Dangerous pattern detection (command substitution, eval, exec, rm -rf)
- Shell command validation (blocks sh/bash -c, requires .sh files)
- File redirect validation (blocks absolute paths and .. traversal)
- Command chaining support with safe operators (&&, ||, ;, |)

Bead ID: contrast-ai-smartfix-action-gad
Tests: 41/41 passing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Added import for command validator in src/config.py
- Implemented _validate_command() method in Config class
- Added validation calls for BUILD_COMMAND and FORMATTING_COMMAND
- Fixed circular import by making CommandValidationError standalone (not inheriting from ConfigurationError)
- Validation only runs in non-testing mode
- Errors are converted from CommandValidationError to ConfigurationError

Integration testing shows:
✓ Valid commands accepted (npm test, mvn build, etc.)
✓ Invalid commands rejected (wget, curl, unknown tools)
✓ Dangerous patterns blocked (rm -rf, command substitution, eval)

Bead ID: contrast-ai-smartfix-action-8re
Tests: 41/41 command validation tests passing
       Manual integration test: 3/3 passing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
- Added comprehensive Security section to README.md
  - Documented all allowed commands by language ecosystem
  - Explained allowed operators and file redirect rules
  - Provided shell command restrictions
  - Listed blocked dangerous patterns
  - Included valid and invalid command examples
  - Added troubleshooting guide for common errors

- Updated security.md with Security Features section
  - Command Allowlist Validation overview
  - Protected configuration parameters
  - Security controls summary
  - Link to detailed README documentation

Documentation covers:
✓ All allowed commands (Java, .NET, Python, Node.js, PHP, build tools)
✓ Command chaining operators (&&, ||, ;, |)
✓ File redirect restrictions (relative paths only)
✓ Shell command rules (no -c flag, .sh files only)
✓ Blocked patterns (command substitution, eval, rm -rf, etc.)
✓ Real-world examples of valid and invalid commands
✓ Troubleshooting guide for validation errors

Bead ID: contrast-ai-smartfix-action-wuv
Final bead for AIML-337 ticket

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Removed unused ALLOWED_COMMANDS import from test_command_validation.py

Linting now passes: make lint ✓

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
This commit addresses 11 critical security and code quality issues
identified during comprehensive code review:

CRITICAL SECURITY FIXES (P1):
- formatter.py: Fix command execution to use shell=True for proper
  operator handling (&&, ||, etc.)
- Block background execution operator (&) while allowing redirects
- Add validation for raw newline characters to prevent injection
- Block Node.js -e and --eval flags for arbitrary code execution
- Restrict Python -m flag to allowlist of safe modules

CODE QUALITY IMPROVEMENTS (P2/P3):
- Add command length limit (10,000 chars) and complexity limit (50 segments)
- Rename contains_dangerous_patterns() to find_dangerous_pattern()
- Pre-compile regex patterns for 65% performance improvement
- Block here-documents (<< and <<<) for command injection
- Extend file descriptor redirect validation (3>, 4>, etc.)
- Block process substitution (<() and >()) operators

TECHNICAL DETAILS:
- Updated run_command() in utils.py to support shell=True parameter
- Enhanced BLOCKED_PATTERNS with proper negative lookbehind/lookahead
- Added DANGEROUS_INTERPRETER_FLAGS and ALLOWED_PYTHON_MODULES constants
- All 369 tests passing
- Linting passes with appropriate complexity exceptions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Add comprehensive prompt for evaluating SmartFix security fixes in E2E test repos.

Changes:
- Add test/prompts/smartfix-pr-review.md (282 lines)
  - Step-by-step PR review process
  - Vulnerability-agnostic evaluation framework
  - Mandatory verification protocol to prevent false positives
  - Detailed security assessment report template
  - Multi-PR pattern analysis

- Add test/prompts/README.md
  - Usage instructions for Claude Code
  - When/why to use the prompt
  - Example output structure

Usage: Run Claude Code in E2E test repo with prompt to systematically
review all open SmartFix PRs and assess security fix effectiveness.

Bead ID: contrast-ai-smartfix-action-z4l
Tests: N/A (documentation only)
Reviews: Completed with findings noted for future iteration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@JacobMagesHaskinsContrast
Copy link
Collaborator Author

Evidence:
Good Ubuntu run (https://github.com/JacobMagesHaskinsContrast/employee-management/actions/runs/20468218399/job/58817122811) made PRs for 9 vulns. The new LLM-as-judge PR review prompt in /tests/prompts/smartfix-pr-review.md worked with Claude to evaluate the PRs and rated them as excellent:

Screenshot 2025-12-23 at 1 48 58 PM

Jacob Mages-Haskins added 3 commits December 23, 2025 13:57
Ignore docs/plans/ and .claude/learnings/ directories from version control.
These contain local planning and AI learning artifacts not intended for the repository.
- Track completion of bead contrast-ai-smartfix-action-z4l (LLM-as-judge prompt)
- Remove .claude/learnings/ from version control per .gitignore update
Remove docs/plans/2025-12-23-command-allowlist-validation-design.md from version control.
File remains on disk but is now ignored per .gitignore update.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements comprehensive command allowlist validation to prevent arbitrary command execution in GitHub Actions workflows. The security feature validates all BUILD_COMMAND and FORMATTING_COMMAND configuration values before execution, blocking dangerous patterns and restricting commands to an approved allowlist of build tools, test frameworks, and formatters.

Key Changes

  • Command validation module with comprehensive allowlist covering Java, .NET, Python, Node.js, PHP, and build tools
  • Integration into Config class with fail-fast validation during initialization
  • Shell command execution support added to run_command() utility
  • Comprehensive test suite with 41 new validation tests

Reviewed changes

Copilot reviewed 16 out of 17 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/smartfix/config/command_validator.py New module implementing command validation with allowlist, dangerous pattern detection, shell restrictions, and redirect validation
src/config.py Integrated command validation into Config class initialization with _validate_command() method
src/utils.py Added shell=True parameter to run_command() to support shell operators in validated commands
src/smartfix/domains/workflow/formatter.py Updated to use shell=True when executing formatting commands
test/test_command_validation.py Comprehensive test suite with 41 tests covering all validation scenarios
README.md Added Security section with detailed command allowlist documentation and examples
security.md Added security features section referencing command allowlist
test/prompts/smartfix-pr-review.md New LLM-as-judge prompt for reviewing SmartFix security fixes in E2E test repos
test/prompts/README.md Documentation for SmartFix review prompts
.beads/* Beads issue tracking system files and configuration

r';\s*rm\b', # rm after command separator
r'\|\s*sh\b', # Piping to shell
r'\|\s*bash\b', # Piping to bash
r'(?<!&)(?<!>)&(?!&)(?![0-9])', # Background execution (&) but not &&, >&1, >&2
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This regex pattern for blocking background execution is complex and difficult to verify. The negative lookbehinds and lookaheads make it hard to reason about edge cases. Consider adding specific test cases that demonstrate what patterns this should and shouldn't match, or split into multiple simpler patterns with clear comments explaining each case.

Copilot uses AI. Check for mistakes.
Comment on lines +87 to +88
if not testing:
self._validate_command("BUILD_COMMAND", self.BUILD_COMMAND)
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Command validation is skipped entirely during testing. While this may be intentional to allow test flexibility, consider adding specific tests that verify the validation behavior by explicitly calling _validate_command() in test scenarios. This ensures the validation logic itself is properly tested even when the Config class is used with testing=True.

Copilot uses AI. Check for mistakes.
Comment on lines +181 to +182
Note:
Complexity is necessary for proper command execution and error handling.
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This note appears to be a defensive comment about code complexity, likely addressing a linter warning. However, the actual complexity issues should be addressed through refactoring rather than documentation. Consider extracting the token masking logic into a separate helper function to reduce the complexity of run_command().

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks strong!

'csharpier',

# Java
'mvn', 'gradle', 'ant', 'junit', 'testng',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we may want to add another java build tool sbt it is mainly for scala but could be used for java repos

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

try:
validate_command(var_name, command)
except CommandValidationError as e:
# Convert CommandValidationError to ConfigurationError
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to log anything here or debug log?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a log message

Jacob Mages-Haskins added 5 commits January 7, 2026 15:35
- Add sbt to allowlist (t5c)
- Add error logging (6t4)
- Add source parameter for config vs AI commands (ue9)
- Add tests for source-based validation (ix3)
- Add source parameter to distinguish config vs AI-generated commands
- Config-sourced commands (from action.yml) skip allowlist validation
- AI-detected commands go through full validation (future feature)
- Add logging for skipped validation
- Default parameter ensures backward compatibility

Bead ID: contrast-ai-smartfix-action-ue9
Tests: 369/369 passing
Reviews: Superpowers code-reviewer - approved
Linting: clean
- Test config-sourced commands skip validation with dangerous patterns
- Test command substitution acceptance for config source
- Test piping to shell acceptance for config source
- Test formatting commands skip validation
- Test backward compatibility with default parameter
- Test empty commands allowed
- Test both build and format commands together

Added 7 tests, all 376 tests passing

Bead ID: contrast-ai-smartfix-action-ix3
Tests: 376/376 passing
Linting: clean
Jacob Mages-Haskins added 6 commits January 8, 2026 11:43
- Add sbt (Scala Build Tool) to ALLOWED_COMMANDS
- Update comment to reflect Java / Scala support
- All 376 tests passing

Bead ID: contrast-ai-smartfix-action-t5c
- Log CommandValidationError details before re-raising
- Provides immediate feedback when AI-generated commands fail validation
- Helps with debugging in CI/CD environments
- All 376 tests passing

Bead ID: contrast-ai-smartfix-action-6t4
return

# Skip validation for config-sourced commands (from humans via action.yml)
if source == "config":
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: This is where we skip the command allowlist validation if the build or format command comes in through the action config file since it is a trusted source. When , in the future, we have AI-generated commands, those AI-generated commands can be filtered through the allowlist like

self._validate_command("FORMATTING_COMMAND", self.FORMATTING_COMMAND, "AI")

… set by humans that come in through the action's config file. In the future, we will put AI-generated commands through this allowlist filter.
@JacobMagesHaskinsContrast JacobMagesHaskinsContrast force-pushed the AIML-337_command-allowlist-validation branch from 53aef2c to e296d84 Compare January 8, 2026 19:01
@JacobMagesHaskinsContrast
Copy link
Collaborator Author

JacobMagesHaskinsContrast commented Jan 9, 2026

I had a successful run of SmartFix: https://github.com/JacobMagesHaskinsContrast/employee-management/actions/runs/20828659601/job/59836794858

Reviewing the PRs made with the testing prompt revealed that SmartFix had made a weak fix for the OS Command Injection vuln, but I'm addressing that in another PR for the backend service.

Screenshot 2026-01-08 at 7 03 05 PM

@JacobMagesHaskinsContrast JacobMagesHaskinsContrast merged commit 4358f39 into main Jan 9, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants