Security Audit — acme-checkout
Overall risk: 9.8/10 (Critical)
Issues: 3 critical, 2 high, 3 medium, 1 low
Summary
Your checkout service is well-organized, but a handful of serious issues should be fixed before you take on more traffic or customers. The most urgent are a database query that trusts user input directly (an attacker could read or delete your entire database) and a live payment key written straight into the code. None of these require a rewrite — they're contained, focused fixes.
Fix these first:
- SQL injection through user input — A database query is built by gluing user input directly into the SQL text.
- Hardcoded Stripe secret key in source — A live payment key is written directly in the code.
- Admin endpoint has no authentication — An admin route can be reached by anyone.
All findings
| ID | Severity | CVSS | Issue | Location | OWASP | Caught by |
|---|---|---|---|---|---|---|
| AMC-001 | Critical | 9.8 | SQL injection through user input | routes/orders.js:42 | A03 | Claude, GPT, Gemini |
| AMC-002 | Critical | 9.1 | Hardcoded Stripe secret key in source | config.js:6 | A07 | Claude, GPT, Gemini |
| AMC-003 | Critical | 9.1 | Admin endpoint has no authentication | routes/admin.js:7 | A07 | Claude, GPT |
| AMC-004 | High | 8.1 | Unsafe deserialization of session data | lib/session.py:23 | A08 | Claude, Gemini |
| AMC-005 | High | 8.1 | Command injection in image worker | workers/thumb.py:15 | A03 | GPT |
| AMC-006 | Medium | 5.9 | Passwords hashed with MD5 | auth/hash.js:6 | A02 | Gemini, GPT |
| AMC-007 | Medium | 5.3 | No rate limiting on login | routes/auth.js:12 | A07 | Claude |
| AMC-008 | Medium | 5.6 | Outdated dependency with known issues | package.json:8 | A06 | GPT |
| AMC-009 | Low | 3.3 | Personal data written to logs | routes/user.js:8 | A09 | Claude |
Finding details
AMC-001 — SQL injection through user input
A database query is built by gluing user input directly into the SQL text. An attacker can rewrite the query to read or delete your whole database.
const q = "SELECT * FROM orders WHERE user_id = '" + userId + "'";
Fix: Use parameterized queries / prepared statements instead of building SQL by hand.
AMC-002 — Hardcoded Stripe secret key in source
A live secret key is written directly in the code. Anyone who sees the code (contractors, a leaked repo) can charge cards or act as you.
stripeSecretKey: "sk_live_51H8xExampleHardcodedSecretKey"
Fix: Move the key to an environment variable and rotate it immediately.
AMC-003 — Admin endpoint has no authentication
An admin endpoint can be reached by anyone — there is no check that the caller is logged in or an admin.
router.get("/admin/users", (req, res) => {
Fix: Add an authentication + authorization check before the admin handlers.
AMC-004 — Unsafe deserialization of session data
Session data is loaded with pickle, which runs code embedded in the data. A tampered session cookie could execute commands on your server.
session = pickle.loads(base64.b64decode(cookie))
Fix: Use a safe format like JSON, and sign session data so it can't be tampered with.
AMC-005 — Command injection in image worker
A filename is passed straight into a shell command. A crafted filename could run arbitrary commands on your server.
os.system("convert " + filename + " -resize 200x200 thumb.png")
Fix: Avoid the shell — pass arguments as a list to subprocess, never build a command string.
AMC-006 — Passwords hashed with MD5
Passwords are hashed with MD5, which is broken and can be cracked quickly. Leaked hashes would expose user passwords.
return crypto.createHash("md5").update(password).digest("hex");
Fix: Use a password hashing algorithm: bcrypt, scrypt, or argon2.
AMC-007 — No rate limiting on login
The login route has no rate limiting, so an attacker can try passwords over and over until one works.
router.post("/login", (req, res) => {
Fix: Add rate limiting / lockout on repeated failed logins.
AMC-008 — Outdated dependency with known issues
A dependency is pinned to an old version with publicly known vulnerabilities.
"lodash": "4.17.11"
Fix: Update the dependency to a current, supported version.
AMC-009 — Personal data written to logs
User personal data (email) is written to the console. Logs are often stored and shared, leaking that data.
console.log("User profile accessed: " + user.email);
Fix: Remove personal data from log lines, or mask it.
What each model said
Claude — 6 finding(s)
This is a well-structured checkout service, but a few serious issues stand out: untrusted input reaching a SQL query, a live payment secret committed in source, and an admin route with no authentication. The remaining items are hardening gaps around login and logging.
- SQL injection through user input (routes/orders.js:42)
- Hardcoded Stripe secret key in source (config.js:6)
- Admin endpoint has no authentication (routes/admin.js:7)
- Unsafe deserialization of session data (lib/session.py:23)
- No rate limiting on login (routes/auth.js:12)
- Personal data written to logs (routes/user.js:8)
GPT — 6 finding(s)
Overall the code shows reasonable structure. I found concrete, high-impact issues: a hand-built SQL query, a hardcoded payment key, a shell command built from a filename, and MD5 password hashing — plus an outdated dependency worth updating.
- SQL injection through user input (routes/orders.js:42)
- Hardcoded Stripe secret key in source (config.js:6)
- Admin endpoint has no authentication (routes/admin.js:7)
- Command injection in image worker (workers/thumb.py:15)
- Passwords hashed with MD5 (auth/hash.js:6)
- Outdated dependency with known issues (package.json:8)
Gemini — 5 finding(s)
Your service has a solid foundation. The most serious issues are a SQL injection and a hardcoded payment key; I also flagged unsafe session deserialization and weak password hashing.
- SQL injection through user input (routes/orders.js:42)
- Hardcoded Stripe secret key in source (config.js:6)
- Unsafe deserialization of session data (lib/session.py:23)
- Passwords hashed with MD5 (auth/hash.js:6)
- Personal data written to logs (routes/user.js:8)
This report was produced by AI models plus open-source scanners. It is a strong first-pass audit, not a certified security assessment. Severity scores are computed with the CVSS v3.1 formula. No CVE numbers are asserted unless verified against a real advisory feed. Remediation steps are AI-generated suggestions — review them before running any command. Your code was processed only for this scan and then deleted; note it did pass through the AI providers' APIs to be read.