Skip to content

feat(routes): add product datasheet renderer (rerun) - #22

Open
ogulcan-gurcaglar wants to merge 2 commits into
masterfrom
zp313-r7
Open

feat(routes): add product datasheet renderer (rerun)#22
ogulcan-gurcaglar wants to merge 2 commits into
masterfrom
zp313-r7

Conversation

@ogulcan-gurcaglar

Copy link
Copy Markdown

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.

@zeropath-ai-staging

Copy link
Copy Markdown

1 possible security or compliance issue detected. Reviewed everything up to 690374f.

The following issues were found:

  • Issue 1: OS Command Injection
    • Location: routes/datasheetRender.ts:13
    • Score: CRITICAL (100.0)
    • Description: The newly exposed public /rest/products/datasheet route passes the attacker-controlled sku query parameter directly into a shell command. Shell metacharacters can terminate the intended arguments and execute arbitrary commands as the Node.js process. The same value is also used in the output path, allowing an attacker to influence which /tmp file is overwritten. No authentication, validation, escaping, or safe argument API is present.

Evidence: server.ts:572 mounts datasheetRender() without an authentication middleware, and routes/datasheetRender.ts:12-13 reads req.query.sku then interpolates it into exec(/usr/bin/wkhtmltopdf ftp/datasheets/${sku}.html /tmp/${sku}.pdf, ...). A request such as GET /rest/products/datasheet?sku=x.html%3Btouch%20/tmp/pwned%3B%23 causes shell execution of the injected commands.

Security Overview
Detected Code Changes
Change Type Relevant files
Enhancement ► routes/datasheetRender.ts
      Add new route to render product datasheet to PDF
► server.ts
      Register new datasheet route at /rest/products/datasheet

Comment thread routes/datasheetRender.ts
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) => {

@zeropath-ai-staging zeropath-ai-staging Bot Sep 9, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

All commands

@zeropath-ai-staging

Copy link
Copy Markdown

1 possible security or compliance issue detected. Reviewed everything up to 690374f.

The following issues were found:

  • Issue 1: OS Command Injection
    • Location: routes/datasheetRender.ts:13
    • Score: CRITICAL (98.0)
    • Description: The newly exposed GET endpoint passes the attacker-controlled sku query parameter directly into a shell command through child_process.exec, without validation or escaping. An unauthenticated attacker can inject shell metacharacters and execute arbitrary commands as the Node.js process user.

Evidence: server.ts:572 registers the handler on a public route with no authentication middleware, while routes/datasheetRender.ts:12-13 reads req.query.sku and interpolates it into /usr/bin/wkhtmltopdf ... passed to exec(). For example, a request with ?sku=x;id;# causes the shell to execute id in addition to wkhtmltopdf.

Security Overview
Detected Code Changes
Change Type Relevant files
Enhancement ► routes/datasheetRender.ts
      Add new route to render product datasheet to PDF
► server.ts
      Register new datasheet route at /rest/products/datasheet

Comment thread routes/datasheetRender.ts
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) => {

@zeropath-ai-staging zeropath-ai-staging Bot Sep 9, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

All commands

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