diff --git a/.github/workflows/ai-security-review.yml b/.github/workflows/ai-security-review.yml index adb8ff9..46b709a 100644 --- a/.github/workflows/ai-security-review.yml +++ b/.github/workflows/ai-security-review.yml @@ -3,18 +3,11 @@ name: Claude Security Review on: pull_request: types: [opened, synchronize, ready_for_review, reopened] - # Optional: only run when security-sensitive areas change - # paths: - # - "src/auth/**" - # - "src/api/**" - # - "infra/**" - # - "config/**" jobs: security: runs-on: ubuntu-latest - # Least privilege for PR review + required OIDC for the Claude GitHub App permissions: contents: read pull-requests: write @@ -24,7 +17,84 @@ jobs: - name: Checkout PR uses: actions/checkout@v6 with: - fetch-depth: 1 + fetch-depth: 2 + + - name: Generate Security Policy Instructions + run: | + cat <<'EOF' > security_policy.md + You are a Principal Application Security Engineer performing a security-focused code review. + + ## CRITICAL – Block PR if found: + - Hardcoded secrets, tokens, credentials + - SQL Injection + - Remote Code Execution + - Path traversal + - Unsafe deserialization + - Missing authentication/authorization on sensitive endpoints + - Sensitive data exposure + + ## HIGH – Must Fix: + - XSS + - SSRF + - IDOR + - CSRF missing protections + - XXE + - Weak cryptography + - Race conditions affecting security + + ## MEDIUM – Fix before production: + - Missing input validation + - Overly permissive CORS + - Missing security headers + - Missing rate limiting + - Dependency vulnerabilities + - Insufficient logging + + ## Technology Specific Checks + + ### Python + - eval(), exec() + - pickle/yaml.load unsafe + - subprocess shell=True + - missing authentication decorators + - weak password hashing + - JWT validation flaws + + ### JavaScript/TypeScript + - innerHTML with user input + - eval()/Function() + - insecure postMessage + - localStorage for sensitive data + - exposed API keys + + ### Infrastructure (Terraform) + - 0.0.0.0/0 ingress + - "*" IAM policies + - unencrypted storage + - public S3 buckets + - missing logging + + ## Output Format + + For each finding: + + :red_circle: CRITICAL | :large_yellow_circle: HIGH | :large_orange_circle: MEDIUM | :large_blue_circle: LOW + + **Issue:** + **Location:** File:Line + **Risk:** + **Fix:** + **Reference:** CWE/OWASP if applicable + + ## Summary + + - Security Score: PASS or FAIL + - Count by severity + - Must-fix before merge + - Positive security practices observed + + Focus strictly on security. Ignore style or performance unless security-related. + EOF - name: Claude security review uses: anthropics/claude-code-action@v1 @@ -34,20 +104,13 @@ jobs: REPO: ${{ github.repository }} PR NUMBER: ${{ github.event.pull_request.number }} - Perform a security-focused review. Prioritize: - - AuthN/AuthZ issues (BOLA/BFLA/BOPLA) - - Injection (SQLi/NoSQLi/Command) - - SSRF, deserialization, crypto misuse - - Sensitive data exposure, logging issues - - Security misconfig in code/config + Below is the mandatory security review policy to follow strictly: + + $(cat security_policy.md) - For each finding, include: - Severity: CRITICAL/HIGH/MEDIUM/LOW - What/Where - Impact - Recommendation + Analyze ALL changes in this PR and produce a structured security review according to the policy above. Use inline comments for line-level issues and one top-level summary comment. claude_args: | - --allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)" + --allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*)" \ No newline at end of file diff --git a/badApi/account.js b/badApi/account.js index 1f1c97c..9ef7770 100644 --- a/badApi/account.js +++ b/badApi/account.js @@ -4,7 +4,7 @@ const router = express.Router(); // In-memory database for storing user information (including sensitive data) const usersInfo = [ { username: 'user1', dob: '1990-01-01', address: '5, 3rd mainland Bridge', cardInfo: '1234-5678-9012-3456', children: ['Child1', 'Child2'], balance: 1000, role: 'user' }, - { username: 'user2', dob: '1985-05-15', address: '7, Ghost street', cardInfo: '9876-5432-1098-7654', children: ['Child3'], balance: 500, role: 'user' }, + { username: 'user3', dob: '1985-05-15', address: '7, Ghost street', cardInfo: '9876-5432-1098-7654', children: ['Child3'], balance: 500, role: 'user' }, ]; /** diff --git a/badApi/admin.js b/badApi/admin.js index 86dc9e2..3367cca 100644 --- a/badApi/admin.js +++ b/badApi/admin.js @@ -5,7 +5,7 @@ const router = express.Router(); const users = []; // Simulated user storage for the sake of example const usersInfo = [ { username: 'user1', dob: '1990-01-01', address: '5, 3rd mainland Bridge', cardInfo: '1234-5678-9012-3456', children: ['Child1', 'Child2'], balance: 1000, role: 'user' }, - { username: 'user2', dob: '1985-05-15', address: '7, Ghost street', cardInfo: '9876-5432-1098-7654', children: ['Child3'], balance: 500, role: 'user' }, + { username: 'user2', dob: '1985-05-17', address: '7, Ghost street', cardInfo: '9876-5432-1098-7654', children: ['Child3'], balance: 500, role: 'user' }, ]; /** diff --git a/badApi/db.js b/badApi/db.js index 2e88a8a..8ad51ef 100644 --- a/badApi/db.js +++ b/badApi/db.js @@ -4,7 +4,7 @@ const mysql = require('mysql2'); const connection = mysql.createConnection({ host: 'localhost', user: 'ghost', - password: 'ghost_sec', //coming back here + password: 'ghost_sec1', //coming back here database: 'badapi_db2' }); diff --git a/badApi/loan.js b/badApi/loan.js index 15eb7fb..d466ab8 100644 --- a/badApi/loan.js +++ b/badApi/loan.js @@ -3,7 +3,7 @@ const router = express.Router(); // In-memory database for loan applications let loanApplications = [ - { username: 'user1', amount: 1000, status: 'pending' }, + { username: 'user1', amount: 5000, status: 'pending' }, ]; /** diff --git a/badApi/otp.js b/badApi/otp.js index 7e76b7f..9fcd780 100644 --- a/badApi/otp.js +++ b/badApi/otp.js @@ -25,7 +25,7 @@ const router = express.Router(); * properties: * otp: * type: integer - * example: 123456 + * example: 1234567 * 500: * description: Internal server error * content: @@ -39,7 +39,7 @@ const router = express.Router(); */ router.post('/otp', (req, res) => { - const otp = Math.floor(100 + Math.random() * 900); // Generate 3-digit random number + const otp = Math.floor(100 + Math.random() * 900); // Generate 3-digit random number. return res.json({ otp }); }); diff --git a/badApi/server.js b/badApi/server.js index a641469..cf21503 100644 --- a/badApi/server.js +++ b/badApi/server.js @@ -20,7 +20,7 @@ app.use(bodyParser.json()); // Swagger setup const swaggerOptions = { swaggerDefinition: { - openapi: '3.0.0', + openapi: '3.0.1', info: { title: 'BadAPI Documentation', version: '1.0.0',