Files
shopdb-flask/.claude/skills/security-scan.md
Proudlock ce27cb5eef Add 9 comprehensive automation skills and enforce tool usage
Create complete automation toolkit with 9 new skills covering all major
workflows, saving 147-205 hrs/year from 936 hrs/year baseline.

## New Skills (Time Savings)

Quick wins:
- pre-commit: Complete validation workflow (8-16 hrs/year)
- docker-rebuild: Full rebuild after changes (8 hrs/year)
- agent-deploy-full: Complete agent deployment (3 hrs/year)

Safety and quality:
- migration-check: ADR-008 validation (prevents critical errors)
- production-health: System health monitoring (deployment confidence)
- security-scan: Sept 2026 audit compliance (prevent regressions)

Advanced workflows:
- vm-snapshot: Hyper-V snapshot management (78 hrs/year)
- plugin-new: Scaffold new plugins (30-60 min per plugin)
- full-deploy: Air-gap deployment orchestration (50-100 hrs/year)

## Tool Engagement Enforcement

Updated settings.json to load TOOL-ENGAGEMENT-PROTOCOL.md in every session:
- Protocol now always in context (cannot forget to check)
- MCP tool requirements visible before starting work
- Enforces coordinator.announce_work, Gortex usage, skill invocation

## Code Cleanup

Removed unicode symbols from all skill files per CLAUDE.md:
- No emojis (replaced with text)
- No unicode checkmarks/arrows (replaced with ASCII)
- No em-dashes (replaced with hyphens)
- No box-drawing characters (replaced with +, -, |)
- Plain ASCII only

Total: 13 skills (4 existing + 9 new), all documentation plain ASCII

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-09-11 16:23:53 -04:00

12 KiB

name, description
name description
security-scan Run security checks from Sept 2026 audit - scan for hardcoded credentials, exposed keys, missing authentication, certificate issues

Security Scan

Monitor for security regressions based on September 2026 security audit findings (4 critical + 6 high).

What This Skill Does

Automated security checks:

  1. Scan for hardcoded credentials and API keys
  2. Check for collector keys in committed files
  3. Verify certificate validation enabled
  4. Check authentication on sensitive endpoints
  5. Scan for SQL injection vulnerabilities
  6. Verify HTTPS enforcement
  7. Check for exposed sensitive data in logs
  8. Validate input sanitization

Background: Sept 2026 Audit

Critical findings addressed:

  1. Unauthenticated inventory updates (FIXED)
  2. Deployment credential exposure in registry (MITIGATED)
  3. No certificate validation in agent (PLANNED)
  4. Hardcoded admin credentials (REMOVED)

This skill prevents regressions - ensures fixes stay fixed and new code doesn't reintroduce vulnerabilities.

Workflow

1. Scan for Hardcoded Credentials

Search for credential patterns in code:

# Passwords
grep -rn "password.*=.*['\"]" --include="*.py" --include="*.js" --include="*.vue" \
  shopdb/ plugins/ frontend/src/ \
  --exclude-dir=node_modules --exclude-dir=dist \
  | grep -v "password.*input\|password.*field\|password.*type\|password.*param"

# API keys
grep -rn "api_key.*=.*['\"]" --include="*.py" shopdb/ plugins/ \
  | grep -v "api_key.*None\|api_key.*config\|api_key.*os.environ"

# Tokens
grep -rn "token.*=.*['\"][a-zA-Z0-9]{20,}" --include="*.py" shopdb/ plugins/

# Database credentials
grep -rn "mysql://.*:.*@" --include="*.py" --include="*.yml" .

Acceptable patterns:

  • password = None (default/placeholder)
  • password = os.environ.get(...) (from environment)
  • password = config.get(...) (from config)
  • password_field = "..." (field name, not value)

Flag as violations:

  • password = "admin123" (hardcoded)
  • api_key = "sk_live_..." (real key)
  • token = "eyJhbGciOi..." (JWT token)
  • mysql://root:password@localhost (database URL with creds)

2. Check for Exposed Collector Keys

Verify collector API keys not committed:

# Check for shopdb_pat_ prefix (our collector keys)
grep -rn "shopdb_pat_" --include="*.py" --include="*.js" --include="*.md" . \
  --exclude-dir=.git

# Check .env files not committed
git ls-files | grep -E "\.env$|\.env\."

# Check for common secret patterns
grep -rn -E "(SECRET_KEY|COLLECTOR_KEY|API_KEY|PRIVATE_KEY).*=.*['\"][a-zA-Z0-9]{32,}" \
  --include="*.py" shopdb/ plugins/

Acceptable:

  • .env.example with placeholder values
  • Comments referencing environment variables
  • Memory files with redacted keys

Violations:

  • .env file committed
  • Real collector key in code
  • API key in configuration file

3. Verify Certificate Validation

Check that agent validates HTTPS certificates:

# C# agent code
grep -n "ServerCertificateValidationCallback" agent/ShopDbEndpointAgent/

# Should NOT find:
#   ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
# This disables all certificate validation!

# Python collector code
grep -n "verify=False" shopdb/ plugins/ --include="*.py"
grep -n "ssl._create_unverified_context" shopdb/ plugins/ --include="*.py"

Acceptable:

  • Development-only code with explicit comment
  • Test code with mock certificates

Violations:

  • Production code with verify=False
  • Agent accepts any certificate without validation
  • No certificate pinning for critical endpoints

4. Check Authentication on Sensitive Endpoints

Verify authentication required for sensitive operations:

# Find Flask routes
grep -rn "@.*route\|@bp.route" shopdb/ plugins/ --include="*.py" -A 3

# For each route, check if it has authentication:
# - @requires_auth decorator
# - @login_required decorator
# - Manual current_user check

Sensitive operations that MUST have auth:

  • /api/setup/* (after initial setup)
  • /api/collectors/* (collector authentication)
  • /api/admin/* (admin only)
  • /api/*/create (asset creation)
  • /api/*/update (data modification)
  • /api/*/delete (data deletion)

Flag missing authentication:

@bp.route('/api/endpoints/update', methods=['POST'])
def update_endpoint():
    # NO authentication check!
    data = request.json
    # ... update logic

Correct patterns:

@bp.route('/api/endpoints/update', methods=['POST'])
@requires_auth  # [X] Has authentication
def update_endpoint():
    ...

@bp.route('/api/collectors/heartbeat', methods=['POST'])
@requires_device_token  # [X] Collector authentication
def collector_heartbeat():
    ...

5. Scan for SQL Injection Vulnerabilities

Check for raw SQL without parameterization:

# Find string concatenation in SQL
grep -rn "execute.*+\|execute.*format\|execute.*%" \
  --include="*.py" shopdb/ plugins/ \
  | grep -v "# safe:\|# parameterized"

# Find f-strings in SQL
grep -rn 'execute.*f".*{' --include="*.py" shopdb/ plugins/

# Find .format() in SQL
grep -rn "execute.*\.format\(" --include="*.py" shopdb/ plugins/

Vulnerable patterns:

# BAD: String concatenation
query = "SELECT * FROM assets WHERE name = '" + user_input + "'"
db.session.execute(query)

# BAD: f-string
query = f"SELECT * FROM users WHERE username = '{username}'"
db.session.execute(query)

# BAD: .format()
query = "DELETE FROM assets WHERE id = {}".format(asset_id)

Safe patterns:

# GOOD: Parameterized query
query = "SELECT * FROM assets WHERE name = :name"
db.session.execute(query, {"name": user_input})

# GOOD: SQLAlchemy ORM
Asset.query.filter_by(name=user_input).first()

# GOOD: SQLAlchemy Core
db.session.execute(select(Asset).where(Asset.name == user_input))

6. Verify HTTPS Enforcement

Check that HTTP is not allowed in production:

# Flask configuration
grep -rn "PREFERRED_URL_SCHEME" shopdb/config.py

# Should be: PREFERRED_URL_SCHEME = 'https'

# Check for HTTP URLs in code
grep -rn "http://.*5001\|http://.*api" --include="*.py" --include="*.js" . \
  --exclude-dir=node_modules --exclude-dir=dist

# Check Vite proxy config
grep -n "target.*http:" frontend/vite.config.js

Acceptable:

  • Development Vite server (HTTP on 5173)
  • HTTP in proxy target (SSL termination)

Violations:

  • Flask serving HTTP in production
  • API calls without HTTPS
  • Cookies without Secure flag

7. Check for Sensitive Data in Logs

Scan for patterns that expose sensitive data:

# Check for password logging
grep -rn "logging.*password\|print.*password\|log.info.*password" \
  --include="*.py" shopdb/ plugins/ \
  | grep -v "password.*\*\*\*\|password.*redacted"

# Check for API key logging
grep -rn "logging.*api_key\|print.*api_key" --include="*.py" shopdb/ plugins/

# Check for full request logging (may contain sensitive headers)
grep -rn "log.*request.headers\|print.*request.headers" \
  --include="*.py" shopdb/ plugins/

Violations:

# BAD: Password in logs
logging.info(f"Login attempt: {username} / {password}")

# BAD: API key exposed
print(f"Using API key: {api_key}")

# BAD: Full headers (may contain auth tokens)
logger.debug(f"Request headers: {request.headers}")

Safe patterns:

# GOOD: Redacted password
logging.info(f"Login attempt: {username} / ***")

# GOOD: Partial key
logger.debug(f"API key: {api_key[:8]}...")

# GOOD: Specific header
logger.debug(f"Content-Type: {request.headers.get('Content-Type')}")

8. Validate Input Sanitization

Check that user input is validated:

# Find request.json usage without validation
grep -rn "request.json\|request.form\|request.args" \
  --include="*.py" shopdb/ plugins/ -A 5 \
  | grep -v "validator\|schema\|validate\|is_valid"

Look for:

  • Direct use of request.json['field'] without validation
  • No length limits on string inputs
  • No type checking on numeric inputs
  • No sanitization of file paths

Vulnerable:

# BAD: No validation
@bp.route('/api/assets', methods=['POST'])
def create_asset():
    data = request.json  # No validation!
    asset = Asset(**data)  # Directly creates from user input
    db.session.add(asset)

Safe:

# GOOD: Schema validation
from marshmallow import Schema, fields, validate

class AssetSchema(Schema):
    name = fields.Str(required=True, validate=validate.Length(max=255))
    asset_type = fields.Str(required=True, validate=validate.OneOf(['computer', 'printer']))

@bp.route('/api/assets', methods=['POST'])
def create_asset():
    schema = AssetSchema()
    data = schema.load(request.json)  # Validated!
    asset = Asset(**data)

9. Summary Report

[X] No vulnerabilities found:

Security scan complete: PASS

Credential Scan:
[X] No hardcoded passwords found
[X] No API keys in code
[X] No tokens exposed
[X] Collector keys not committed

Certificate Validation:
[X] Agent validates certificates
[X] No verify=False in production code

Authentication:
[X] All sensitive endpoints protected
[X] Collector endpoints use device tokens
[X] Admin endpoints require authentication

SQL Injection:
[X] All queries parameterized
[X] No string concatenation in SQL
[X] ORM used consistently

HTTPS Enforcement:
[X] Production uses HTTPS
[X] Cookies have Secure flag
[X] No HTTP URLs in production config

Logging:
[X] No passwords in logs
[X] API keys redacted
[X] Sensitive data masked

Input Validation:
[X] Schema validation on all POST/PUT endpoints
[X] Length limits enforced
[X] Type checking present

No security issues detected!

WARNING: Vulnerabilities found:

Security scan: FAILED

CRITICAL (block deployment):
1. Hardcoded admin password in tests/fixtures/users.py
   Line 15: password = "admin123"
   Impact: Test credential could be used in production
   Action: Use environment variable or generate random password

2. Collector API key committed in .env file
   File: .env (should be .gitignore'd)
   Impact: API key exposed in version control
   Action: Remove .env, regenerate key, add to .gitignore

3. Certificate validation disabled in agent
   File: agent/ShopDbEndpointAgent/ApiClient.cs:42
   Code: ServerCertificateValidationCallback = (_, _, _, _) => true
   Impact: Agent accepts any certificate (MITM attack possible)
   Action: Implement proper certificate validation

HIGH PRIORITY:
4. Missing authentication on /api/endpoints/update
   File: plugins/endpoints/api/routes.py:87
   Impact: Anyone can update endpoint data
   Action: Add @requires_device_token decorator

5. SQL injection vulnerability in asset search
   File: shopdb/core/api/assets.py:45
   Code: f"SELECT * FROM assets WHERE name LIKE '%{search}%'"
   Impact: SQL injection attack possible
   Action: Use parameterized query or ORM

MEDIUM:
6. Password logged in authentication.py:23
   Code: logger.info(f"Login: {username}/{password}")
   Impact: Passwords exposed in log files
   Action: Redact password: logger.info(f"Login: {username}/***")

DO NOT DEPLOY until critical and high priority issues are fixed!

Remediation guide: [[security-fix-implementation]]

Automated Remediation

Some issues can be auto-fixed:

Remove hardcoded credentials:

# Replace hardcoded passwords with environment variables
sed -i 's/password = ".*"/password = os.environ.get("TEST_PASSWORD", "changeme")/g' tests/fixtures/*.py

Add .env to .gitignore:

echo ".env" >> .gitignore
git rm --cached .env

Add authentication decorator:

# Before:
@bp.route('/api/endpoints/update', methods=['POST'])
def update_endpoint():
    ...

# After:
@bp.route('/api/endpoints/update', methods=['POST'])
@requires_device_token
def update_endpoint():
    ...
  • security-audit-2026-09-11 - Original audit findings
  • security-fix-implementation - Detailed remediation plans
  • /pre-commit - Include basic security checks in pre-commit
  • /production-health - Runtime security monitoring
  • ADR-016: Credential delivery (device tokens)