All jobs

Run a Security Audit on a Go App

Yes. An agent builds and runs your Go service in its own sandbox, checks each finding against the running binary, and writes a report without touching code.

Run this on RushIn a Project that has your repository.

What the agent does

The agent clones the repository into its own cloud sandbox and reads how it builds and what it already checks before it reads a handler. In a Go service like miniflux/v2, go.mod declares module miniflux.app/v2 with go 1.26.0, main.go is four lines that call internal/cli, and the Makefile defines test as go test -cover -race -count=1 ./..., lint as go vet, a gofmt check and golangci-lint run, and run as go run main.go with RUN_MIGRATIONS=1, CREATE_ADMIN=1 and an admin password set in the environment. .golangci.yml enables gocritic, staticcheck, sqlclosecheck and loggercheck. The agent installs the Go toolchain the module asks for, starts Postgres in the sandbox, runs make run, and signs in as the created admin so every finding is checked against a live server.

Then it maps the trust boundaries from the code, not from a checklist. internal/http/server/ holds the server, routes, metrics and health check; internal/api/middleware.go validates X-Auth-Token against stored API keys and sets CORS headers; internal/ui/web_session_middleware.go, csrf_middleware.go and auth_proxy_middleware.go guard the web UI, with the CSRF check comparing the session token to the form value or header in constant time; internal/http/request/client_ip.go decides which IP to trust behind a proxy; internal/reader/fetcher/request_builder.go fetches feeds from URLs users supply; and internal/mediaproxy/ rewrites and proxies images. Each of those is a place where user input meets a privilege, so each gets a section.

For each area the agent writes requests against the running app and reads the tests that already exist. For feed fetching it reads the private-network tests in request_builder_test.go, which show the fetcher refuses private addresses by default and allows them only when configured, and then tries a feed URL pointing at the sandbox's own loopback to confirm the refusal. For the API it checks what an invalid or missing X-Auth-Token returns and whether the CORS headers reflect an arbitrary origin. For the UI it submits a state-changing form without the csrf field, inspects the Set-Cookie attributes on the session cookie, and checks the response headers the internal/http/response/html.go and internal/ui/proxy.go set, including the Content-Security-Policy. For the configuration it reads internal/config/ for options like CreateAdmin, HTTPClientMaxBodySize and MetricsPassword and checks what the defaults expose.

It also runs the dependency and code checks the sandbox can do in minutes: govulncheck ./... against go.mod and go.sum, gosec over internal/, and make test to see that the race detector passes. A finding is kept only when the agent reproduced it against the running binary or read it in a test; a tool warning it could not reproduce is listed separately as unconfirmed.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "claude",
  "input": "Audit this Go service for security problems and write security-audit.md. First read go.mod, main.go, the Makefile, the linter config and the CI workflow, and record the Go version, the build and test commands, and what the project already checks. Start any database the service needs in the sandbox, build and run the service with the documented local command, create or sign in as the first user, and confirm it answers. Map the trust boundaries from the code: authentication and session middleware, CSRF, API key handling, CORS, cookie attributes, response security headers, proxy and client IP trust, outbound fetching of user-supplied URLs, file and media handling, and configuration defaults. For each, make real requests against the running service and read the existing tests, then record every finding with the file and line, one request that demonstrates it, its severity, and the fix. Run govulncheck and gosec and list their results, marking anything you could not reproduce as unconfirmed. Change no code and open no pull request.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
  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, with a download link good for an hour that reading the session again renews. It opens with how the service was built and run: the Go version from go.mod, the Postgres the sandbox started, the make run command with the environment it used, the admin account it created, and the port it answered on, so every finding is tied to known conditions.

Then come the findings, grouped by boundary: authentication and sessions, CSRF, API keys and CORS, headers and cookies, proxy trust, outbound fetching, media proxying, configuration defaults, and dependencies. Each has the file:line, the exact request the agent sent and the response it got, a severity, and a fix in one or two sentences. A separate section lists what was checked and found sound, with the test or request that showed it, and another lists tool output the agent could not reproduce.

A reviewer reads the request behind each finding and can replay it against their own instance, checks the govulncheck section against the module versions they ship, and confirms the clone is clean: no commit, no pull request, no edited file. The transcript keeps every request and its response beside the report.

Run it on every release branch

Run the audit before each release rather than once a year. In the console, add an automation to the Project with this prompt and a GitHub trigger on pull_request.opened filtered to pull requests into your release branch, and each one gets a fresh report as its run's artifact with the event added after the prompt. A schedule trigger with a monthly cron in your timezone covers the default branch between releases.

From your own server, POST /o/{org}/sessions with this prompt and the repository in resources starts one on demand, and a webhook_url on the key POSTs run.completed with the session_url to fetch the report from.

The use case this job follows, with its automation and trigger: Produce a report or file, no repo.

Why run it on Rush?

A finding from reading code alone is a hypothesis; a request that demonstrates it against the running binary is evidence. The sandbox has the Go toolchain, Docker for Postgres and a browser, so the agent builds, runs and signs in to the service and attaches the request and response to each finding. The reviewer replays the request instead of trusting the sentence.

The audit touches nothing. It runs in its own sandbox on its own clone, with no access to production and no permission to push, and the result is a file with citations and reproductions. Running govulncheck, gosec, the race-detected test suite and a full session of hand-made requests takes a developer most of a day on a laptop; here it runs in the background while they do something else, and the transcript shows every command.

Frequently asked questions

Will it change anything in my repository?

No. The prompt forbids changing code and opening a pull request, and the report is a session artifact. If you want fixes, start a second run with the report attached as a document block and a prompt that asks for a pull request, or reply to the same session with that follow-up.

What if my service needs Postgres, Redis or an S3 bucket to start?

The agent reads the local run instructions and starts what it can in the sandbox with Docker. Miniflux needs Postgres, which the Makefile and the integration test workflow both describe, so the agent starts it and sets DATABASE_URL. A dependency it cannot start is recorded in the report's setup section, and the affected checks are marked as static.

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

Each finding carries the request the agent sent and the response it received, or the test it read, with the file:line behind the behavior. Tool output from gosec or govulncheck that the agent could not reproduce goes in a separate unconfirmed list rather than among the findings.

Can it audit a private repository?

Yes. Install the Rush GitHub App on the repository and name it in resources; the run clones it through that installation into its own sandbox, and only your org can read the session and its artifact.

Does it run my existing test suite?

Yes, once, with the project's own command. For Miniflux that is make test, which runs with the race detector and coverage on, and the report notes whether it passed and which security-relevant tests exist, such as the private-network tests for the feed fetcher.