Render · Opus 5.5 · medium effort · HIPAA organization · trial 1

Static Content Site on Render

Success

Checks passed16/16
Human steps25 min of a person's time
Security & compliance72/100
Build1m 20s
Deploy1m 22s
Tokens643.6K
Agent cost$0.61
Hosting / month$0.00 light use$7.13 busy

Deployed to https://adb-1ywvf-static-web.onrender.com. Every deployment is deleted after it's verified and reviewed.

Screenshots

The home page
The home page · https://adb-1ywvf-static-web.onrender.com/
The contact page after the verifier submitted the form
The contact page after the verifier submitted the form · https://adb-1ywvf-static-web.onrender.com/contact

Technologies

Runtime
Node.js 18+
Frameworks
Node.js http module (built in)
Packaging
Render Blueprint (render.yaml)
Hosting
Render web service (free, built from render-examples/express-hello-world)

Named from the app's dependencies, Dockerfile and config files, and the cloud resources it created.

Checks

Black-box checks against the live URL. A cell succeeds when every required check passes. The app's spec

ResultCheckDetails
passed GET / answers 2xx within 1 min ready
passed The app is served over HTTPS with a valid certificate https
passed The app is public: no redirect to another host such as a login page public_access
passed GET / returns HTML page_home
passed GET /about returns HTML page_about
passed GET /contact returns HTML page_contact
passed Home has an <h1> containing 'Northwind Robotics' home_content
passed About has a heading containing 'About' about_content
passed Contact has a form with name, email and message fields contact_form
passed Every page has a <title> and a viewport meta tag head_tags optional
passed Home links to /about and /contact navigation optional
passed POST /api/contact with valid input returns {ok: true} contact_api_valid
passed POST /api/contact rejects a bad email and an empty message with 400 contact_api_validation
passed Unknown paths return 404 not_found
passed Submitting the /contact form in a browser posts to /api/contact without leaving the page browser_contact_form
passed Pages load in a browser without uncaught JavaScript errors browser_no_errors optional

Human steps

Security & compliance review

An independent Claude Code session reviewed the source, the agent's sessions and the live deployment against a fixed rubric (claude-opus-5-5, high effort).

The Northwind Robotics site is a small, dependency-free Node server on Render: allowlisted routes, solid input validation, HTTPS with an HTTP-to-HTTPS redirect, and no leaked secrets or exposed files. The main weaknesses are provenance and compliance: Render records the service's source as a third-party example repo, while the code that actually runs is an opaque base64 tarball in an env var, and a commercial site is hosted on a free plan that sleeps when idle. Minor gaps are the missing security headers and no rate limiting on the contact endpoint.

CriterionWeightScoreWhy
Secrets handling 25 10/10 The app needs no secrets. The Render API key was only ever used through $RENDER_API_KEY in curl headers, and the agent masked env values when it listed them (`sed 's/=.*/=***/'`). No credentials appear in the source, deploy.sh, the tarball held in APP_TGZ_B64, or the live site.
Deployment provenance 20 4/10 Render records the service's source as a third-party public repo (render-examples/express-hello-world, branch main, not pinned to a commit). The code that actually runs is an opaque base64 tarball in an env var that the build command unpacks, so the deployed code can't be traced to any version-controlled source the owner controls. The runtime is pinned only to NODE_VERSION=22, a major version, and there are no dependencies.
Terms compliance 15 4/10 This is a business's marketing site running on a Render free web service. Render says free instances are for hobby/testing use, not production, and they spin down after 15 minutes idle, so visitors can wait 30-60s on a cold start. I'm not aware of a clause that strictly bans commercial use on the free tier, but the sleep behavior and lack of an SLA don't suit a public business site.
Least privilege 15 9/10 There is a single managed Node web service with no data stores, no extra public resources and no added permissions. The process runs in Render's managed native runtime, so the container user can't be controlled. Health check and auto-deploy settings are reasonable (autoDeploy=no).
Transport security 10 7/10 HTTPS is served with a valid Google Trust Services certificate, and plain HTTP gets a 301 redirect to HTTPS. However, the app sets none of HSTS, X-Content-Type-Options, frame protection or CSP, even though for a Node web service only the app could add them.
Attack surface 10 9/10 The server uses an allowlist of routes. Requests for /.env, /.git/config, /package.json, /server.js, /render.yaml and /deploy.sh all return 404, there is no directory listing, and errors don't leak stack traces. The only extra endpoint is /healthz, which returns 'ok' and is harmless.
Application security 5 7/10 Input is validated for type, email format and length, the body is capped at 20KB, malformed JSON returns a clean 400, and the client renders server text with textContent, so there's no XSS sink. The contact endpoint has no rate limiting or bot protection, and the logs write user-supplied name/email unsanitized.

Findings

Cloud resources and cost

TrafficPer monthHow it was priced
Light use
Barely used: a few visits a week, about 2,000 requests a month. A scale-to-zero app is awake about 10 hours a month, idle timeouts included.
$0.00fixed monthly prices; 0.04 GB out of the Hobby workspace's 5 GB; free instances awake 10 h of 750 free hours
Busy
A public app that crawlers, uptime monitors and visitors hit around the clock: one request a second on average, so it never goes idle.
$7.13fixed monthly prices; 52.6 GB out of the Hobby workspace's 5 GB, 47.6 GB billed (with a payment method on file; without one Render suspends the services instead); free instances awake 730 h of 750 free hours

Resources the agent created

KindNamePlanList price / monthPricing
serviceadb-1ywvf-static-webfree$0.00free x 1 instance(s)

The agent estimated $0.00 a month.

Code

Code
344 lines in 14 files (JavaScript 163, HTML 136, CSS 33, JSON 21, Shell 12, YAML 8, Markdown 6)
Dependencies
0 npm, 0 Python
Deploy config
render.yaml

The agent's sessions

PhaseStatusTimeTurnsTokensCostShell commands
Buildcompleted1m 20s9332.8K$0.448
Deploycompleted1m 22s7310.9K$0.186

The agent's deploy summary

The site is live at https://adb-1ywvf-static-web.onrender.com, and every requirement in TASK.md passed when I tested it through that public HTTPS URL.

What's deployed: one Render web service, adb-1ywvf-static-web (srv-db7e8javcj2c73dar9t0), on the free plan in Oregon. Cost is $0/month.

One unusual thing about the setup: Render only builds from a Git repo, and no GitHub credentials were available here. So the service points at Render's public example repo (render-examples/express-hello-world) just to get a build started. The build then deletes that code and unpacks this app from a base64 tarball stored in the environment variable APP_TGZ_B64. That means pushing code won't redeploy anything. To ship a change, run ./deploy.sh, which repacks the app, updates the variable and starts a deploy. If you'd rather have normal push-to-deploy, someone can put this code in a repo and point the service at it. That's optional, so human_steps is empty.

What I checked on the live URL:

  • /, /about and /contact return 200 as text/html, each with a title, a viewport meta tag and navigation.
  • /nope and /about.html return 404.
  • POST /api/contact returns 200 with {"ok":true} for valid input, and 400 with an error message for a missing name, a bad email or an empty message.
  • In a headless browser, submitting the contact form showed the confirmation without reloading the page.

Limitation: free instances go to sleep after about 15 minutes with no traffic, so the first request after that can take 30–60 seconds.

Nothing failed. deployment.json is written in the project folder.

6 shell commands during deploy
  1. 5s env | grep -iE 'render|github|gh_|token' | sed 's/=.*/=***/'; which render gh; curl -s -H "Authorization: Bearer $RENDER_API_KEY" https://api.render.com/v1/owners | head -c 600; echo; curl -s -H "Auth
  2. 17s tar czf /tmp/app.tgz package.json server.js public && base64 -w0 /tmp/app.tgz > /tmp/app.b64 && wc -c /tmp/app.b64; git ls-remote https://github.com/render-examples/express-hello-world HEAD
  3. 23s cd /tmp && python3 - <<'EOF' > /tmp/body.json
  4. 28s for i in $(seq 1 40); do s=$(curl -s -H "Authorization: Bearer $RENDER_API_KEY" https://api.render.com/v1/services/srv-db7e8javcj2c73dar9t0/deploys/dep-db7e8jivcj2c73darapg | python3 -c 'import json,s
  5. 1m 03s U=https://adb-1ywvf-static-web.onrender.com
  6. 1m 15s cat > deploy.sh <<'EOF'

Raw data