Skip to content

Platform Bridge - Security Documentation

Security analysis and best practices fer the platform bridge module.

Security Model

The platform bridge follows a delegation security model where authentication and authorization be handled by official CLI tools (gh and az), not by the bridge itself.

Core Principles

  1. No Credential Storage: Bridge never stores or handles credentials
  2. CLI Authentication: Delegates all authentication to gh/az CLI tools
  3. Input Validation: All user inputs be validated before subprocess calls
  4. Safe Subprocess: Parameterized commands prevent shell injection
  5. Fail Secure: Errors don't leak sensitive information

Authentication Delegation

GitHub Authentication

The bridge uses gh CLI fer all GitHub operations:

# Bridge NEVER handles GitHub tokens directly
bridge = PlatformBridge()  # No tokens or credentials passed

# Authentication handled by gh CLI
issue = bridge.create_issue(title="Test", body="Body")
# Under the hood: gh uses credentials from ~/.config/gh/hosts.yml

User Authentication Flow:

  1. User runs: gh auth login
  2. GitHub CLI authenticates through OAuth
  3. Credentials stored in ~/.config/gh/hosts.yml
  4. Bridge calls gh commands which use stored credentials

Benefits:

  • Bridge code never sees tokens
  • GitHub handles token refresh
  • Standard gh security model applies

Azure DevOps Authentication

The bridge uses az CLI fer all Azure DevOps operations:

# Bridge NEVER handles Azure DevOps PATs directly
bridge = PlatformBridge()  # No tokens or credentials passed

# Authentication handled by az CLI
issue = bridge.create_issue(title="Test", body="Body")
# Under the hood: az uses credentials from ~/.azure/

User Authentication Flow:

  1. User runs: az login
  2. Azure CLI authenticates through browser
  3. Credentials stored in ~/.azure/
  4. Bridge calls az commands which use stored credentials

Benefits:

  • Bridge code never sees tokens or PATs
  • Azure handles token refresh
  • Standard az security model applies

Input Validation

All user inputs be validated before bein' passed to subprocess calls.

Title Validation

def _validate_title(title: str) -> None:
    """Validate issue/PR title"""
    if not title or not title.strip():
        raise ValueError("Title cannot be empty")

    if len(title) > 256:
        raise ValueError("Title too long (max 256 characters)")

    # No shell metacharacters in title
    dangerous_chars = ['$', '`', '$(', '|', '&', ';']
    if any(char in title for char in dangerous_chars):
        raise ValueError(f"Title contains invalid characters: {dangerous_chars}")

Branch Name Validation

def _validate_branch_name(branch: str) -> None:
    """Validate git branch name"""
    if not branch or not branch.strip():
        raise ValueError("Branch name cannot be empty")

    # Git branch name rules
    invalid_patterns = ['..',  '~', '^', ':', '\\', '*', '?', '[']
    if any(pattern in branch for pattern in invalid_patterns):
        raise ValueError(f"Branch name contains invalid patterns")

    if branch.startswith('/') or branch.endswith('/'):
        raise ValueError("Branch name cannot start or end with /")

Body/Description Validation

def _validate_body(body: str) -> None:
    """Validate issue/PR body"""
    if not body or not body.strip():
        raise ValueError("Body cannot be empty")

    # No null bytes (can confuse subprocess)
    if '\x00' in body:
        raise ValueError("Body contains null bytes")

    # Reasonable size limit (prevent DoS)
    if len(body) > 65536:  # 64KB
        raise ValueError("Body too large (max 64KB)")

Safe Subprocess Usage

All subprocess calls use parameterized commands to prevent shell injection.

Correct Pattern (Safe)

# SAFE - Command and args as list
subprocess.run(
    ["gh", "issue", "create", "--title", title, "--body", body],
    capture_output=True,
    text=True,
    timeout=30
)

Why this be safe:

  • Command and arguments passed as list
  • No shell interpretation
  • Arguments can't be interpreted as commands
  • Even if title/body contain ; rm -rf /, they be treated as literal strings

Anti-Pattern (Unsafe)

# UNSAFE - Don't do this!
subprocess.run(
    f"gh issue create --title '{title}' --body '{body}'",
    shell=True,  # ❌ Dangerous!
    capture_output=True
)

Why this be dangerous:

  • Shell interprets the entire string
  • Special characters in title/body can execute commands
  • Example attack: title = "test'; rm -rf /; echo '"

Timeout Protection

All subprocess calls have timeouts to prevent hangs:

result = subprocess.run(
    cmd,
    capture_output=True,
    text=True,
    timeout=30  # 30 second timeout
)

Timeout Values:

  • Standard operations: 30 seconds
  • CI status checks: 60 seconds (can be slow)
  • Large file uploads: 120 seconds

Error Handling

Errors be handled to prevent information leakage:

Safe Error Messages

try:
    result = subprocess.run(cmd, ...)
    if result.returncode != 0:
        # Don't expose full command in error
        raise RuntimeError(f"Operation failed: {sanitize_error(result.stderr)}")

except subprocess.TimeoutExpired:
    # Don't expose what command timed out
    raise RuntimeError("Operation timed out after 30 seconds")

except Exception as e:
    # Don't expose internal details
    raise RuntimeError(f"Unexpected error: {type(e).__name__}")

Information Leakage Prevention

What we DON'T expose:

  • Full subprocess commands (might contain sensitive args)
  • File system paths (might reveal directory structure)
  • Internal stack traces (might reveal implementation details)

What we DO expose:

  • Operation type (e.g., "create issue failed")
  • User-actionable guidance (e.g., "run gh auth login")
  • Error categories (e.g., "authentication required")

Filesystem Security

The bridge reads git configuration but never writes to filesystem (except through CLI tools).

Read-Only Operations

# Bridge only reads git config
def _get_git_remote(repo_path: Path) -> str:
    """Read git remote URL (read-only)"""
    result = subprocess.run(
        ["git", "remote", "-v"],
        cwd=repo_path,
        capture_output=True,
        text=True
    )
    return result.stdout

No Filesystem Writes

The bridge never writes to:

  • Git configuration (.git/config)
  • Credential files (~/.config/gh/, ~/.azure/)
  • System directories
  • Temporary files with sensitive data

All writes be handled by official CLI tools which have their own security models.

Threat Model

Threats We Mitigate

  1. Shell Injection: Parameterized commands prevent command injection
  2. Credential Theft: No credentials stored or handled by bridge
  3. Information Leakage: Error messages don't expose sensitive details
  4. DoS via Large Inputs: Size limits on all inputs
  5. Path Traversal: Repository paths validated

Threats Out of Scope

These be handled by CLI tools or operating system:

  1. Network Security: gh/az CLI handle HTTPS connections
  2. Token Refresh: CLI tools manage token lifecycle
  3. Multi-Factor Auth: Handled by GitHub/Azure DevOps
  4. Rate Limiting: CLI tools handle API rate limits
  5. Audit Logging: Platform services log all operations

Trust Boundaries

User Code → PlatformBridge → gh/az CLI → GitHub/Azure DevOps API
   ↑            ↑                ↑              ↑
   |            |                |              |
   |            |                |              +-- Trusted (official API)
   |            |                +----------------- Trusted (official CLI)
   |            +---------------------------------- Trusted (our code)
   +----------------------------------------------- Untrusted (user input)

Trust Assumptions:

  • User input be UNTRUSTED (validate everything)
  • gh/az CLI tools be TRUSTED (official tools)
  • Platform APIs be TRUSTED (GitHub/Azure)
  • Operating system be TRUSTED (subprocess isolation)

Security Best Practices

For Users

  1. Keep CLI Tools Updated:
# GitHub CLI
gh version  # Check current version
brew upgrade gh  # Update (macOS)

# Azure CLI
az version  # Check current version
brew upgrade azure-cli  # Update (macOS)
  1. Use Secure Authentication:
# GitHub - Use OAuth, not PATs
gh auth login  # Follow OAuth flow

# Azure - Use browser auth
az login  # Opens browser
  1. Review Permissions:
# GitHub - Check token permissions
gh auth status

# Azure - Check account permissions
az account show
  1. Rotate Credentials Regularly:
# GitHub - Refresh auth
gh auth refresh

# Azure - Re-login periodically
az logout && az login

For Developers

  1. Never Add Credential Parameters:
# ❌ WRONG - Don't add token parameters
def create_issue(self, title: str, token: str):
    ...

# ✅ RIGHT - Delegate to CLI
def create_issue(self, title: str):
    subprocess.run(["gh", "issue", "create", ...])
  1. Always Validate Inputs:
# ✅ RIGHT - Validate before subprocess
def create_issue(self, title: str, body: str):
    self._validate_title(title)
    self._validate_body(body)
    subprocess.run([...])
  1. Use Parameterized Commands:
# ✅ RIGHT - List of args
subprocess.run(["gh", "issue", "create", "--title", title])

# ❌ WRONG - String with shell=True
subprocess.run(f"gh issue create --title '{title}'", shell=True)
  1. Set Timeouts:
# ✅ RIGHT - Always set timeout
subprocess.run(cmd, timeout=30)

# ❌ WRONG - No timeout (can hang forever)
subprocess.run(cmd)

Security Audit Checklist

When reviewin' platform bridge code:

  • No credential storage or handling
  • All subprocess calls use list (not string with shell=True)
  • All user inputs validated before subprocess
  • Timeouts set on all subprocess calls
  • Error messages don't leak sensitive info
  • No filesystem writes except through CLI tools
  • Branch names validated against git rules
  • Size limits enforced on all inputs
  • No null bytes in string inputs
  • Exception handling prevents info leakage

Reporting Security Issues

If ye discover a security vulnerability in the platform bridge:

  1. Don't open a public GitHub issue
  2. Do email security@amplihack.dev with details
  3. Include:
  4. Description of vulnerability
  5. Steps to reproduce
  6. Potential impact
  7. Suggested fix (if ye have one)

We'll respond within 48 hours and coordinate a fix.

See Also