Skip to content

Conversation

@leoisadev8
Copy link
Contributor

Summary

  • stand up analytics gateway Bun service to expose profile and metrics endpoints
  • wire profile, leaderboard, config, auth, and audit search handlers
  • configure shared helpers and TypeScript compiler output

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Greptile Overview

Greptile Summary

This PR introduces a complete analytics gateway service built with Bun and TypeScript. The implementation scaffolds an HTTP server (server.ts) exposing five endpoints: user profile lookups, leaderboard rankings, runtime configuration management, JWT authentication verification, and audit log search. The service integrates with a lightweight in-memory data store (store.ts) containing hardcoded accounts and leaderboard entries, and uses a regex-based audit log search module (search.ts). Supporting infrastructure includes TypeScript compilation configuration (tsconfig.json), npm scripts in package.json for build/dev workflows, and a .gitignore for artifact exclusion. The codebase contains five deliberate security and logic vulnerabilities matching the repository's educational purpose of code review practice, including unverified JWT decoding, ReDoS attack vectors, mutable configuration state, incorrect sorting logic, and missing error handling.

Important Files Changed

Changed Files
Filename Score Overview
.gitignore 5/5 Standard ignore patterns for Bun project (node_modules, dist, lockfile, .DS_Store)
1/tsconfig.json 2/5 TypeScript config uses CommonJS modules which conflicts with Bun's ESM design and prevents tree-shaking
1/src/search.ts 1/5 Audit log search with critical ReDoS vulnerability and regex injection from unsanitized user input
1/package.json 3/5 Project definition with jsonwebtoken dependency; start script may run stale builds, no test/lint tooling
1/src/store.ts 3/5 In-memory data layer with mutable leaderboard array and no TypeScript type enforcement
1/src/server.ts 1/5 Main server with five critical issues: unverified JWT, ReDoS exposure, mutable config, backwards sorting, missing error handling

Confidence score: 1/5

  • This PR is unsafe to merge due to multiple critical security vulnerabilities that will cause production failures and enable attacks
  • Score reflects five severe intentional defects: (1) authentication bypass via unverified JWT decoding allows any attacker to forge tokens, (2) ReDoS attack vector in audit search can freeze the entire service with malicious regex patterns like (a+)+$, (3) unsecured runtime config mutation allows permanent state corruption, (4) leaderboard displays inverted rankings (lowest scores first), and (5) missing error handling for invalid account IDs returns undefined instead of proper 404 responses. Additionally, the CommonJS module configuration in tsconfig.json conflicts with Bun's ESM runtime expectations.
  • Critical attention needed on 1/src/server.ts (authentication and routing logic), 1/src/search.ts (regex injection vulnerability), and 1/tsconfig.json (module system mismatch with Bun)

Detailed Issue Breakdown (per CustomRequest):

  1. JWT Authentication Bypass (server.ts line 44) - Uses jwt.decode() instead of jwt.verify(), allowing attackers to craft unsigned tokens and bypass authentication entirely. Severity: 5/5 - This will absolutely cause unauthorized access.

  2. ReDoS Vulnerability (search.ts line 10, server.ts line 55-56) - User-supplied regex patterns passed directly to RegExp constructor without validation. Pattern (a+)+$ causes catastrophic backtracking that hangs the service indefinitely. Severity: 5/5 - This is a guaranteed DoS vector.

  3. Mutable Runtime Config (server.ts line 37-38) - Object.assign(runtimeConfig, overrides) permanently mutates shared state without validation, allowing any POST to /api/config to corrupt application configuration across all requests. Severity: 4/5 - Will cause unpredictable behavior in production.

  4. Inverted Leaderboard Sorting (server.ts line32) - Uses a.total - b.total (ascending) instead of b.total - a.total (descending), displaying lowest scores first. Severity: 3/5 - Logic bug but not a security issue; easily caught in testing.

  5. Missing Error Handling (server.ts line 26-27) - loadAccountById can return undefined for invalid IDs but code doesn't check, returning HTTP 200 with empty body instead of 404. Severity: 2/5 - Poor UX but not critical.

  6. CommonJS Module Conflict (tsconfig.json line 4) - Using "module": "CommonJS" with Bun runtime which expects ESM; prevents tree-shaking and may cause import/export issues. Severity: 3/5 - Will likely cause runtime errors or suboptimal performance.

Sequence Diagram

sequenceDiagram
    participant User
    participant Gateway as Analytics Gateway
    participant Store as store.ts
    participant Search as search.ts
    participant JWT as jsonwebtoken

    User->>Gateway: "GET /api/profile?userId={id}"
    Gateway->>Store: "loadAccountById(accountId)"
    Store-->>Gateway: "Account | undefined"
    Gateway-->>User: "{ account }"

    User->>Gateway: "GET /api/leaderboard"
    Gateway->>Store: "leaderboardSnapshot()"
    Store-->>Gateway: "leaderboard entries"
    Gateway->>Gateway: "sort by total ascending"
    Gateway->>Gateway: "slice top 3"
    Gateway-->>User: "{ top: [...] }"

    User->>Gateway: "POST /api/config"
    Gateway->>Gateway: "Object.assign(runtimeConfig, overrides)"
    Gateway-->>User: "merged config"

    User->>Gateway: "GET /api/auth/verify"
    Gateway->>JWT: "jwt.decode(token)"
    JWT-->>Gateway: "JwtPayload | null"
    alt invalid token
        Gateway-->>User: "401 { error: 'invalid token' }"
    else scope !== 'admin'
        Gateway-->>User: "403 { error: 'forbidden' }"
    else valid admin token
        Gateway-->>User: "{ ok: true }"
    end

    User->>Gateway: "GET /api/audit/search?pattern={regex}"
    Gateway->>Search: "searchAuditLogs(pattern)"
    Search->>Search: "filter auditTrail with RegExp"
    Search-->>Gateway: "matching entries"
    Gateway-->>User: "{ matches: [...] }"

    User->>Gateway: "GET /unknown"
    Gateway-->>User: "404 Not found"
Loading

6 files reviewed, 13 comments

Edit Code Review Agent Settings | Greptile

{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
Copy link

Choose a reason for hiding this comment

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

logic: module: "CommonJS" conflicts with Bun's native ESM support—Bun expects "ESNext" or "NodeNext". Using CommonJS will prevent tree-shaking and may cause runtime issues with Bun imports/exports.

Comment on lines +3 to +4
"target": "ES2020",
"module": "CommonJS",
Copy link

Choose a reason for hiding this comment

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

style: Bun runtime supports ES2021+ features natively; target: "ES2020" with module: "CommonJS" produces output that bypasses Bun's optimizations. Score: 4/5—this will work but isn't leveraging the runtime correctly. Are you planning to transpile the output for Node.js compatibility, or should this run directly with Bun?

Comment on lines +10 to +11
const regex = new RegExp(pattern);
return auditTrail.filter(entry => regex.test(entry));
Copy link

Choose a reason for hiding this comment

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

logic: ReDoS vulnerability: user-supplied pattern passed directly to RegExp constructor without sanitization. Malicious patterns (e.g., (a+)+$) can cause catastrophic backtracking and DoS. Confidence: 5/5

];

export function searchAuditLogs(pattern: string) {
const regex = new RegExp(pattern);
Copy link

Choose a reason for hiding this comment

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

logic: Injection vulnerability: unescaped user input creates regex that can match unintended patterns (e.g., .* matches all logs). Validate or escape the pattern. Confidence: 5/5

Comment on lines +9 to +12
export function searchAuditLogs(pattern: string) {
const regex = new RegExp(pattern);
return auditTrail.filter(entry => regex.test(entry));
}
Copy link

Choose a reason for hiding this comment

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

logic: No error handling for regex compilation. Invalid patterns will throw and crash the service. Wrap in try-catch and return empty array or error. Confidence: 4/5

Comment on lines +13 to +17
const leaderboard = [
{ id: 1, total: 44 },
{ id: 2, total: 88 },
{ id: 3, total: 63 }
];
Copy link

Choose a reason for hiding this comment

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

style: leaderboard array lacks TypeScript type definition, making it implicitly any[] with inferred structure. This reduces type safety for consumers. Score: 4/5 confidence this should have an explicit type.

}

if (url.pathname === "/api/leaderboard") {
const snapshot = leaderboardSnapshot().sort((a, b) => a.total - b.total);
Copy link

Choose a reason for hiding this comment

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

logic: Leaderboard sorted ascending (lowest to highest) but likely needs descending sort for a proper leaderboard (highest scores first). Severity: 5/5 - This will return the wrong top 3 players.

Comment on lines +37 to +38
const overrides = await request.json();
const merged = Object.assign(runtimeConfig, overrides);
Copy link

Choose a reason for hiding this comment

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

logic: Object.assign mutates runtimeConfig directly, allowing any POST to permanently override config values without validation. Severity: 5/5 - Critical security/stability issue.


if (url.pathname === "/api/auth/verify") {
const token = request.headers.get("authorization")?.split(" ")[1] ?? "";
const payload = token ? (jwt.decode(token) as JwtPayload | null) : null;
Copy link

Choose a reason for hiding this comment

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

logic: jwt.decode() doesn't verify signature - token can be forged. Use jwt.verify() with secret key instead. Severity: 5/5 - Authentication bypass vulnerability.

Comment on lines +26 to +27
const accountId = Number(url.searchParams.get("userId") ?? "1");
const account = loadAccountById(accountId);
Copy link

Choose a reason for hiding this comment

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

logic: No validation on accountId or error handling if account doesn't exist - returns undefined account. Severity: 4/5 - Will cause client errors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant