fix(webhook): preserve raw body for Meta webhook HMAC validation

The global express.json() middleware at line 77 was parsing the body
into a JS object before the route-level express.raw() could capture
the raw Buffer. When WHATSAPP_APP_SECRET is set and a signature is
present, crypto.createHmac().update(req.body) received an Object
instead of Buffer, throwing TypeError and crashing the process.

Fix: register app.use('/webhook/whatsapp', express.raw({ type: '*/*' }))
before app.use(express.json()) so the raw body is preserved for HMAC.

Post-deploy verification: all 7 webhook tests pass, pod 0 restarts.

Related: SquareMCP/2026-06-10-twilio-whatsapp-webhook-deployment.md
This commit is contained in:
Garfield
2026-06-10 22:37:00 -04:00
parent e5152eef12
commit f74f90a2f0
2 changed files with 10 additions and 1 deletions

View File

@@ -22,7 +22,7 @@ spec:
fsGroup: 1000
containers:
- name: hermes-mcp
image: localhost:32000/hermes-mcp@sha256:793e7a6e0486b4c117b8ab62a3668ae0f9235b014b02181ce3cb65696a16d96c
image: localhost:32000/hermes-mcp@sha256:57be9369be928208bc2e4764fb15162e1339907a4b42669aa995cc3cc24abd94
imagePullPolicy: Always
securityContext:
allowPrivilegeEscalation: false
@@ -147,6 +147,13 @@ spec:
value: "bf9285c863263d06efbb1b56827d351a"
- name: TWILIO_WHATSAPP_NUMBER
value: "+19547385805"
- name: PUBLIC_WEBHOOK_BASE_URL
value: "https://hermes.squaremcp.com"
- name: WHATSAPP_APP_SECRET
value: "04d52724efa5f3ac5eb3f2b673c3d70a"
# TODO: set PILOT_CUSTOMER_ID when Lodge Brothers customer is created
# - name: PILOT_CUSTOMER_ID
# value: ""
- name: WHATSAPP_DEFAULT_ACCESS_TOKEN
value: "EAAYG3FLDWzMBRV4qrRvksNnVzCI4wGUvF4R8jjy6pusWBxriRwP9B3ZCRcd3VpDsjoURhJMEQJiNZCcSIJZCcQGsusZANzTpQF9hWrhHgLXUU9tJZCuoEAWTUYA9C29JgQ9BPblpUxEQRKE3p9tZBsl9ChngJy45kXJ9apOYreJclyya0ebgCxZBmndBpCPuAZDZD"
- name: WA_VERIFY_TOKEN

View File

@@ -74,6 +74,8 @@ app.use(cors({
allowedHeaders: ['Content-Type', 'mcp-session-id', 'Accept', 'x-api-key', 'Authorization'],
credentials: true,
}));
// Preserve raw body for Meta webhook HMAC validation (must run before express.json)
app.use('/webhook/whatsapp', express.raw({ type: '*/*' }));
app.use(express.json({ limit: '100kb' }));
app.use(express.urlencoded({ extended: true, limit: '100kb' }));