-
Notifications
You must be signed in to change notification settings - Fork 3
Sec #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Sec #11
Changes from all commits
77b0f31
f17854b
5c4bc52
216a3e0
422dc35
caafe23
2f96571
58acb27
93403f1
9689240
be0e8f0
385e713
94eee11
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :large_orange_circle: MEDIUM — Shell Substitution Issue: Risk: The security review runs with no effective policy guidance, silently degrading review quality while appearing functional. Fix: Use a prior step to capture the file contents and expose it as a step output or environment variable, then reference it with - name: Load security policy
id: policy
run: echo "content=$(cat security_policy.md)" >> $GITHUB_OUTPUT
- name: Claude security review
with:
prompt: |
${{ steps.policy.outputs.content }}
...Or inline the policy directly into the |
||
|
|
||
| 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:*)" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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' }, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Severity: HIGH — Hardcoded PII and Credit Card Numbers in Source Code + Data Inconsistency Introduced by This PR This line contains a full, unmasked credit card number ( Additionally, this PR renames the username from Impact:
Recommendation:
Comment on lines
6
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 CRITICAL — Hardcoded PII and Payment Card Data in Source Code Issue: Full credit card numbers ( Risk:
Fix: Use obviously fake, clearly-marked test data that cannot be confused with real credentials: // SAFE TEST DATA — clearly synthetic, not real PAN format
{ username: 'user1', dob: 'XXXX-XX-XX', address: 'TEST_ADDRESS', cardInfo: 'TEST-CARD-XXXX', ... }Never store card numbers — even partial — in application code. Use a tokenization service for any payment card reference. Reference: CWE-312 (Cleartext Storage of Sensitive Information) | OWASP A02:2021 | PCI-DSS Requirement 3 |
||
| ]; | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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' }, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Severity: CRITICAL — Broken Function-Level Authorization on Admin Endpoints This PR changes a DoB in the seed data, but the critical issue is the surrounding module: Similarly, Impact: Complete privilege escalation — any unauthenticated user can become an admin, then grant themselves or others arbitrary balance increases. Recommendation:
Comment on lines
7
to
+8
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 CRITICAL — Hardcoded PII and Payment Card Data in Source Code Issue: Same pattern as Risk: Identical to Fix: Replace with clearly synthetic, obviously-fake test data. Consider a shared test-fixtures module rather than duplicating data across files. Reference: CWE-312 | OWASP A02:2021 | PCI-DSS Requirement 3 |
||
| ]; | ||
|
|
||
| /** | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -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 | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Severity: CRITICAL — Hardcoded Database Credential The password was changed from Impact: Anyone with read access to the repository (or git history) gains the database password. Even if the password is rotated, the old value survives in history unless a full history rewrite is performed. Recommendation:
|
||||||
| database: 'badapi_db2' | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 CRITICAL — Hardcoded Database Credential Issue: Database password is hardcoded directly in source code. Rotating from Risk: Anyone with read access to the repository (or any git clone / fork / leak) has the database password. Credentials committed to git cannot be truly revoked from history without a rewrite. Fix:
Suggested change
Store all credentials in environment variables and inject them at runtime (e.g., via Reference: CWE-798 (Use of Hard-coded Credentials) | OWASP A02:2021 Cryptographic Failures |
||||||
| }); | ||||||
|
|
||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,7 +25,7 @@ const router = express.Router(); | |
| * properties: | ||
| * otp: | ||
| * type: integer | ||
| * example: 123456 | ||
| * example: 1234567 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Severity: LOW — Swagger Example Contradicts Implementation The example was updated to Recommendation: Fix the underlying OTP generation (see comment on line 42), then update the example to reflect the corrected 6-digit format. |
||
| * 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. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Severity: CRITICAL — Insecure OTP: Weak Entropy + Trivial Brute Force + Exposed in Response Three compounding problems on this line:
Impact: OTP can be trivially predicted or brute-forced, enabling account takeover of any user. Recommendation: const otp = crypto.randomInt(100000, 999999); // 6-digit CSPRNG OTP
// Send via SMS/email; do NOT return in response
res.json({ message: 'OTP sent' });Add per-IP and per-user rate limiting (e.g., max 5 attempts, 15-minute lockout). |
||
| return res.json({ otp }); | ||
|
Comment on lines
+42
to
43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :large_yellow_circle: HIGH — Weak OTP: Non-Cryptographic Randomness + Trivial Brute-Force Surface + Secret Returned to Caller Issue (Line 42) — CWE-338: Issue (Line 42) — 3-digit space: Issue (Line 43) — Sensitive Data Exposure: The OTP is returned directly in the HTTP response to the requester. A valid OTP flow sends the secret out-of-band (SMS, email, authenticator app) to a verified channel — it must never be returned to the API caller, or it provides zero authentication value. Fix: const { randomInt } = require('crypto');
router.post('/otp', (req, res) => {
// 6-digit, cryptographically secure OTP — sent out-of-band, NOT returned
const otp = randomInt(100000, 999999);
// sendOtpViaSms(req.user.phone, otp); // deliver to verified channel
return res.json({ message: 'OTP sent' }); // never return the OTP value
});Also add rate limiting (e.g., 3 attempts per 15 minutes) and expiry (e.g., 5-minute TTL). Reference: CWE-338 (Weak PRNG) | CWE-330 (Insufficient Randomness) | OWASP A02:2021 | NIST SP 800-63B |
||
| }); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
:large_orange_circle: MEDIUM — Security Control Modified by the PR Under Review
Issue: This PR modifies the very workflow that performs security review. An attacker (or a developer with write access) could weaken or disable security checks — remove severity categories, drop findings, whitelist vulnerabilities — and the weakened policy would govern the review of the same PR that introduced the change.
Risk: Security review becomes self-referentially ineffective. This is analogous to asking a contractor to write their own safety inspection checklist.
Fix: Protect
.github/workflows/with a CODEOWNERS rule requiring approval from a dedicated security team member before workflow changes can be merged:Consider also using
pull_request_targetfor the security review trigger so it always runs from the base branch policy, not the PR branch — though notepull_request_targethas its own risks and requires careful scoping.Reference: OWASP CI/CD Security Top 10 — CICD-SEC-4 (Poisoned Pipeline Execution)