Skip to content

fix(activation-service): stop leaking internal errors, drop unused KYC_PUBLIC_KEY - #1109

Merged
sameh-farouk merged 2 commits into
developmentfrom
fix/activation-service-error-exposure
Jul 26, 2026
Merged

fix(activation-service): stop leaking internal errors, drop unused KYC_PUBLIC_KEY#1109
sameh-farouk merged 2 commits into
developmentfrom
fix/activation-service-error-exposure

Conversation

@sameh-farouk

Copy link
Copy Markdown
Member

Two follow-ups from #1105. Supersedes #1107, which GitHub auto-closed when #1105 merged and its branch — #1107's base — was deleted. Same content, rebased onto development.

1. Internal error messages were returned to callers

The error middleware computed http-errors' expose flag and then ignored it. Both branches of the NODE_ENV check sent the message anyway, because lodash's omit(err, ['stack']) copies message through:

omit(httpError(500, 'Insufficient Balance Error: ...'), ['stack'])
// => {"message":"Insufficient Balance Error: ...","status":500,"statusCode":500,"expose":false}
//                                                                              ^^^^^^^^^^^^^^

And the development branch — the default, since NODE_ENV is set in neither the Dockerfile nor the chart — sent the whole error including the stack trace. Every deployment has been running in that mode.

Verified against the built image before the fix: a request that failed because the funding account was empty replied with Insufficient Balance Error: Failed to apply 'transfer' on section 'balances' with args '<address>,1000000.

Now the flag decides:

400 -> {"message":"substrateAccountID is not a valid account id"}
500 -> {"message":"Internal Server Error"}        # log: "error happened handling the request"

NODE_ENV no longer affects what is returned, so a deployment cannot leak by omitting it — which is what every deployment does today.

Behaviour change: bodies are consistently { message }. 4xx previously also carried status, statusCode and expose; non-http errors fell through to res.send(err.message) as text rather than JSON. The frontend catches errors and renders a fixed string without reading the body, so there is no UI impact.

2. KYC_PUBLIC_KEY was required but unread

In bin/www's required env variables since the service was written, but nothing reads it: the signature verification was commented out years ago and its only caller, POST /activation/create-entity, was removed in #1103 as an unauthenticated route that signed a fee-paying extrinsic from the service wallet. Requiring an unused variable only gives the service a reason to refuse to start.

Removed from the required list, the chart and the documented .env. Re-add it alongside the verification code if KYC checks return.

While in the readme, two claims that no longer held: it documented the removed /activation/create-entity endpoint, and said activation "puts 500 tokens" on an account — true in 2021, since reduced by three orders of magnitude.

Verification

  • lint + unit: 27/27
  • against live devnet: 400 exposes its message, 500 returns Internal Server Error while the underlying error still reaches the log, service boots with no KYC_PUBLIC_KEY set, SIGTERM exits 0

🤖 Generated with Claude Code

https://claude.ai/code/session_011YKJm3zuWdSepriT9KL9zy

…llers

The error middleware computed http-errors' `expose` flag and then ignored it.
Both branches of the NODE_ENV check sent the message regardless: lodash's
`omit(err, ['stack'])` copies `message` through, so the "production" path replied
with things like a decoded chain error next to `expose: false`, and the
development path — the default, since NODE_ENV is set in neither the Dockerfile
nor the chart — added the stack trace on top.

Concretely, a request that failed because the funding account was empty replied
with `Insufficient Balance Error: Failed to apply 'transfer' on section
'balances' with args '<address>,1000000.` Verified against the built image.

Now the flag decides: 4xx keeps its message, because the caller sent something
unusable and needs to know what; 5xx returns the generic status text and the real
error goes to the log only. Responses are consistently JSON, where a non-http
error used to fall through to `res.send(err.message)` as text.

NODE_ENV no longer changes what is returned, so a deployment cannot leak by
omitting it — which is what every deployment does today.
`KYC_PUBLIC_KEY` has been in bin/www's required env variables since the service
was written, but nothing reads it: the signature verification was commented out
years ago, and its only caller — `POST /activation/create-entity` — was removed
in #1103 as an unauthenticated route that signed a fee-paying extrinsic from the
service wallet. A variable that is required but unused only gives the service a
reason to refuse to start.

Removed from the required list, the chart, and the documented .env. Re-add it
alongside the verification code if KYC checks come back.

While in the readme, two claims that no longer hold: it documented the removed
`/activation/create-entity` endpoint, and said activation "puts 500 tokens" on an
account — the amount at the time, since reduced by three orders of magnitude.
@sameh-farouk
sameh-farouk requested a review from LeeSmet as a code owner July 26, 2026 15:49
@sameh-farouk
sameh-farouk force-pushed the fix/activation-service-error-exposure branch from 6c90479 to b902ddf Compare July 26, 2026 15:51
@sameh-farouk
sameh-farouk merged commit 7460a4e into development Jul 26, 2026
3 checks passed
@sameh-farouk
sameh-farouk deleted the fix/activation-service-error-exposure branch July 26, 2026 15:53
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