# Run a Security Audit on a Node.js App

Yes. An agent runs your Node.js app in its own sandbox, confirms each finding against the running app, and writes a report without changing your code.

[Run this on Rush](https://cloud.getrush.ai/run/security-audit/nodejs/).

## What the agent does

The agent clones the app into its own cloud sandbox and reads how it starts before it reads any route. In an Express app like OWASP/NodeGoat, `package.json` says `npm start` runs `node server.js`, `config/env/all.js` reads `MONGODB_URI` and falls back to `mongodb://localhost:27017/nodegoat`, and `docker-compose.yml` pins `mongo:4.4` and runs `node artifacts/db-reset.js` before the server. The agent starts MongoDB in the sandbox, seeds it with `db-reset.js` (which creates the `admin`, `user1` and `user2` accounts), starts the server on port 4000 and signs in as an ordinary user, so every finding is checked against the running app rather than argued from source alone.

Then it walks the routes in `app/routes/index.js` into their data-access files and groups what it finds by the OWASP categories the prompt names. For injection it reads how `app/data/allocations-dao.js` builds a Mongo `$where` query from the `threshold` query parameter and how `app/routes/contributions.js` passes request fields to `eval`. For broken access control it reads `app/routes/allocations.js`, where `displayAllocations` takes `userId` from `req.params` rather than the session, and the `/learn` handler in `index.js` that redirects to a URL from the query string. For each one it records the file and line, sends one request to the running app that demonstrates the behaviour, and notes what the response shows.

Authentication and sensitive-data findings come from the same reading. In `app/routes/session.js` the sign-up validation uses `PASS_RE = /^.{1,20}$/`, so it accepts any short password, and `server.js` leaves the session cookie's `secure` flag commented out while `saveUninitialized` is `true`. In `app/data/profile-dao.js` the agent reads which fields (`ssn`, `dob`, `bankAcc`) are stored and whether they are encrypted, and in `server.js` it reads which `helmet` protections are commented out. Every finding carries a severity the agent assigns from impact and how easily it is reached.

The prompt says to change no code, so the agent only reads and sends requests; it writes nothing back to the repository and opens no pull request. The whole audit, every command it ran and every response it saw, stays in the session transcript, and the result is `security-audit.md` returned as an artifact on the session. Because NodeGoat is insecure on purpose with documented issues, the report can be scored against known answers, which is what makes it a fair test of an agent's audit.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "Clone https://github.com/OWASP/NodeGoat and run it in the sandbox: start MongoDB, seed it with artifacts/db-reset.js, start the server on port 4000 and sign in as an ordinary user. Audit it for injection, broken access control, authentication flaws and sensitive data exposure. For each finding write the file and line, one request that demonstrates it against the running app, its severity and the fix, in security-audit.md. Change no code and open no pull request."
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

What comes back is `security-audit.md` as an artifact on the session, which the session read returns with a download link good for an hour. It opens with how the app was run (the MongoDB version, the seed script, the port and the account it signed in as) so a reader knows the exact conditions each finding was checked under. Then it lists findings grouped by category: injection, broken access control, authentication, and sensitive data exposure.

Each finding names the file and line, states the behaviour in one or two sentences, shows the request the agent sent and what the response showed, gives a severity, and gives the fix in terms of the code it points at: take `userId` from the session instead of `req.params`, parse the `threshold` parameter as an integer, replace `eval` with a numeric parse, tighten the password rule, set the cookie's `secure` and `httpOnly` flags, enable the `helmet` protections that are commented out.

A reviewer checks the report against the app before acting on it: that each cited line is really there, that the request shown does what the report says, and that the severity matches the impact for their own deployment. Because the sandbox still holds the running app, a follow-up message to the same session can ask the agent to prove any finding again or to prepare the fixes as a pull request.

## Run it on every a pull request to the default branch

Add an automation to the Project with a `github` trigger on `pull_request.opened` and `pull_request.synchronize`, filtered with `branch_patterns` to your default branch, and this prompt. Each push to a pull request then gets a read-only run that checks the routes it touched in `app/routes/` and the queries under `app/data/` against MongoDB, and comments the findings on the pull request with file and line, so an injection in a new DAO call is caught before review.

Set a webhook URL on the API key and Rush POSTs `run.completed` when the turn finishes, with the `session_url`. Your server reads the session, takes the link to `security-audit.md` from its artifacts, and attaches it to the pull request or opens a tracking issue, so a new flaw is caught the day it is introduced rather than at the next manual review.

## Why run it on Rush?

A security audit means running the target and sending it real requests, which you do not want pointed at your own machine or your shared staging environment. In a Rush sandbox the agent starts the database, seeds it, runs the app and probes it on its own disk and network, and nothing it does reaches your laptop, your network or another tenant. When the run ends the sandbox is torn down.

An audit is only worth acting on if you can check it. Because every request and every response is kept in the session transcript, the person reading `security-audit.md` can trace each finding to the exact exchange that demonstrated it instead of taking the agent's word. Several audits can run at once, one per application, up to the key's concurrent-run limit.

## Frequently asked questions

### Will it change anything in my repository?

No. The prompt says to change no code and open no pull request. The agent reads the code and sends requests to the copy running in its own sandbox. What comes back is a Markdown report you download from the session's artifacts.

### Does it need a database?

For NodeGoat, yes: it needs MongoDB. The agent starts MongoDB in the sandbox and seeds it with the repository's own artifacts/db-reset.js before starting the server, so the findings are checked against a running app with real data rather than read from source only.

### Can it audit a private app?

Yes. Install the Rush GitHub App on the repository and add it to the request as a resource, {"url": "https://github.com/your-org/your-app"}, instead of naming a public URL in the prompt. The agent starts with that repository already cloned and runs it the same way.

### How do I know the findings are real and not guessed?

Each finding carries the request the agent sent and what the response showed, and the full exchange is in the session transcript. You can replay any request yourself, or ask the same session to demonstrate it again, because its sandbox still has the app running.
