Describe the bug
Two custom routes on the API gateway are reachable without any authentication, and one of them lets anyone create leave records for arbitrary employees.
1. POST /api/webhooks/slack — no signature verification, no auth (api-gateway-node/index.js:616-651)
The handler takes a Slack-style payload and calls the leave service directly:
const { user_name, text } = req.body;
// ...
const employeeId = user_name; // <- attacker-controlled
await axios.post(`${LEAVE_SERVICE_URL}/api/leave/request`, { employeeId, ... }, ...)
There is no Slack signing-secret HMAC check, no x-internal-key requirement — anyone who can reach the gateway can POST a body with user_name = any employee id, text = "paid leave starting tomorrow", and a leave request is created on behalf of that employee. The upstream error message from leave-service is also echoed back verbatim into the JSON response (minor info leak on top).
2. POST /api/billing/create-checkout-session — no auth middleware at all (api-gateway-node/index.js:653-676)
This route isn't under any /api/{protected-prefix} that runs authMiddleware. It falls back to req.user?.tenant_id ?? 'default', and since no user exists, an unauthenticated caller can freely create checkout sessions with a client-chosen "tenant" and plan parameters. It also hits an undefined/incomplete upstream — so it's both open and half-wired.
Steps to reproduce
curl -X POST http://localhost:8080/api/webhooks/slack -H 'Content-Type: application/json' -d '{"user_name":"<any employee id>","text":"requesting leave"}' → upstream leave request is created, no auth needed
curl -X POST http://localhost:8080/api/billing/create-checkout-session -d '{"plan":"pro","amount":999}' → no 401
Expected behavior
Webhook endpoints validate the sender (Slack signature / shared secret); billing routes sit behind authMiddleware + RBAC.
Actual behavior
Both callable anonymously; Slack path can enqueue leave requests as any employee.
Files involved
services/api-gateway-node/index.js:616-651 (slack webhook)
services/api-gateway-node/index.js:653-676 (billing)
services/api-gateway-node/index.js:461-463 (public-path bypass list)
Suggested fix
- Slack: verify the signature (Slack signing secret / HMAC-SHA256) or require an internal API key before forwarding to leave-service.
- Billing: add it to the protected prefix list and validate
req.user.
Happy to submit a PR for both.
Environment
- docker compose, branch
main @ 4afc605
Describe the bug
Two custom routes on the API gateway are reachable without any authentication, and one of them lets anyone create leave records for arbitrary employees.
1.
POST /api/webhooks/slack— no signature verification, no auth (api-gateway-node/index.js:616-651)The handler takes a Slack-style payload and calls the leave service directly:
There is no Slack signing-secret HMAC check, no
x-internal-keyrequirement — anyone who can reach the gateway can POST a body withuser_name= any employee id,text= "paid leave starting tomorrow", and a leave request is created on behalf of that employee. The upstream error message from leave-service is also echoed back verbatim into the JSON response (minor info leak on top).2.
POST /api/billing/create-checkout-session— no auth middleware at all (api-gateway-node/index.js:653-676)This route isn't under any
/api/{protected-prefix}that runsauthMiddleware. It falls back toreq.user?.tenant_id ?? 'default', and since no user exists, an unauthenticated caller can freely create checkout sessions with a client-chosen "tenant" and plan parameters. It also hits an undefined/incomplete upstream — so it's both open and half-wired.Steps to reproduce
curl -X POST http://localhost:8080/api/webhooks/slack -H 'Content-Type: application/json' -d '{"user_name":"<any employee id>","text":"requesting leave"}'→ upstream leave request is created, no auth neededcurl -X POST http://localhost:8080/api/billing/create-checkout-session -d '{"plan":"pro","amount":999}'→ no 401Expected behavior
Webhook endpoints validate the sender (Slack signature / shared secret); billing routes sit behind
authMiddleware+ RBAC.Actual behavior
Both callable anonymously; Slack path can enqueue leave requests as any employee.
Files involved
services/api-gateway-node/index.js:616-651(slack webhook)services/api-gateway-node/index.js:653-676(billing)services/api-gateway-node/index.js:461-463(public-path bypass list)Suggested fix
req.user.Happy to submit a PR for both.
Environment
main@4afc605