feat(routes): add product datasheet renderer (rerun) - #22
feat(routes): add product datasheet renderer (rerun)#22ogulcan-gurcaglar wants to merge 2 commits into
Conversation
|
❌ 1 possible security or compliance issue detected. Reviewed everything up to 690374f. The following issues were found:
Evidence:
Security Overview
Detected Code Changes
|
| module.exports = function datasheetRender () { | ||
| return (req: Request, res: Response, next: NextFunction) => { | ||
| const sku = req.query.sku ?? '' | ||
| exec(`/usr/bin/wkhtmltopdf ftp/datasheets/${sku}.html /tmp/${sku}.pdf`, (error, stdout) => { |
There was a problem hiding this comment.
OS Command Injection in datasheetRender route (Severity: CRITICAL)
The datasheet endpoint is vulnerable to OS command injection by interpolating the attacker-supplied sku query parameter into a shell command, which causes arbitrary commands to run as the Node.js process and can overwrite arbitrary /tmp files. This occurs in routes/datasheetRender.ts where req.query.sku is interpolated into exec(/usr/bin/wkhtmltopdf ftp/datasheets/${sku}.html /tmp/${sku}.pdf). Evidence shows unauthenticated access via server.ts:572 that mounts this function without validation, enabling inputs like sku=x.html;touch /tmp/pwned;# to execute commands.
View details in ZeroPath
Suggested fix
Unable to apply as inline suggestion. Download .diff and apply from repo root with git apply 13d2f2b1.diff
diff --git a/routes/datasheetRender.ts b/routes/datasheetRender.ts
--- a/routes/datasheetRender.ts
+++ b/routes/datasheetRender.ts
@@ -4,13 +4,17 @@
*/
import { type Request, type Response, type NextFunction } from 'express'
-import { exec } from 'child_process'
+import { execFile } from 'child_process'
// Renders a product datasheet to PDF for the storefront download button.
module.exports = function datasheetRender () {
return (req: Request, res: Response, next: NextFunction) => {
- const sku = req.query.sku ?? ''
- exec(`/usr/bin/wkhtmltopdf ftp/datasheets/${sku}.html /tmp/${sku}.pdf`, (error, stdout) => {
+ const sku = req.query.sku
+ if (typeof sku !== 'string' || !/^[a-zA-Z0-9_-]+$/.test(sku)) {
+ res.status(400).send('Invalid SKU')
+ return
+ }
+ execFile('/usr/bin/wkhtmltopdf', [`ftp/datasheets/${sku}.html`, `/tmp/${sku}.pdf`], (error, stdout) => {
if (error != null) {
next(error)
return
💬 Reply @ZeroPath false-positive because … or @ZeroPath accepted-risk because … to triage this finding, or ask it any question.
|
❌ 1 possible security or compliance issue detected. Reviewed everything up to 690374f. The following issues were found:
Evidence:
Security Overview
Detected Code Changes
|
| module.exports = function datasheetRender () { | ||
| return (req: Request, res: Response, next: NextFunction) => { | ||
| const sku = req.query.sku ?? '' | ||
| exec(`/usr/bin/wkhtmltopdf ftp/datasheets/${sku}.html /tmp/${sku}.pdf`, (error, stdout) => { |
There was a problem hiding this comment.
OS Command Injection in datasheetRender.ts (sku param) (Severity: CRITICAL)
An attacker can inject arbitrary shell commands via the sku query parameter which is interpolated into a shell invocation, leading to remote code execution with the Node.js process user. This happens in routes/datasheetRender.ts where req.query.sku is interpolated into /usr/bin/wkhtmltopdf ... and executed, with the public route registered in server.ts:572 and no authentication.
View details in ZeroPath
Suggested fix
Unable to apply as inline suggestion. Download .diff and apply from repo root with git apply c2abb0e9.diff
diff --git a/routes/datasheetRender.ts b/routes/datasheetRender.ts
--- a/routes/datasheetRender.ts
+++ b/routes/datasheetRender.ts
@@ -4,13 +4,13 @@
*/
import { type Request, type Response, type NextFunction } from 'express'
-import { exec } from 'child_process'
+import { execFile } from 'child_process'
// Renders a product datasheet to PDF for the storefront download button.
module.exports = function datasheetRender () {
return (req: Request, res: Response, next: NextFunction) => {
- const sku = req.query.sku ?? ''
- exec(`/usr/bin/wkhtmltopdf ftp/datasheets/${sku}.html /tmp/${sku}.pdf`, (error, stdout) => {
+ const sku = typeof req.query.sku === 'string' && /^[\w-]+$/.test(req.query.sku) ? req.query.sku : ''
+ execFile('/usr/bin/wkhtmltopdf', [`ftp/datasheets/${sku}.html`, `/tmp/${sku}.pdf`], (error, stdout) => {
if (error != null) {
next(error)
return
💬 Reply @ZeroPath false-positive because … or @ZeroPath accepted-risk because … to triage this finding, or ask it any question.
Controlled re-run: tree is byte-identical to the pre-deploy probe branch, so discovery prompts hit the AI cache and only the confirmation stage differs.