{"record":{"id":"916c6fb4b94d8454","repo":"yikart/AiToEarn","slug":"channelwebhookinvalidsignature-916c6f","errorCode":null,"errorMessage":"ChannelWebhookInvalidSignature","messagePattern":"ChannelWebhookInvalidSignature","errorType":"http","errorClass":null,"httpStatus":401,"severity":"error","filePath":"project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/instagram/instagram-webhook.provider.ts","lineNumber":41,"sourceCode":"\n@Injectable()\nexport class InstagramWebhookProvider implements PlatformWebhookHandler {\n  private readonly logger = new Logger(InstagramWebhookProvider.name)\n\n  constructor(\n    private readonly config: InstagramConfig,\n    @Optional() private readonly publishRecordRepo?: PublishRecordRepository,\n    @Optional() private readonly stateService?: PublishStateService,\n  ) {}\n\n  async handle(request: Request, response: Response): Promise<void> {\n    if (request.method === 'GET') {\n      this.handleChallenge(request, response)\n      return\n    }\n    if (!this.verify(request)) {\n      this.logger.warn({ platform: AccountType.Instagram }, 'Instagram webhook signature invalid')\n      response.status(401).send(getCodeMessage(ResponseCode.ChannelWebhookInvalidSignature, undefined, getLocale()))\n      return\n    }\n    const body = this.parseMetaBody(request)\n    if (!body) {\n      response.status(200).send('EVENT_RECEIVED')\n      return\n    }\n    if (body.object && body.object !== InstagramWebhookObject.Instagram) {\n      response.status(200).send('EVENT_RECEIVED')\n      return\n    }\n    for (const entry of body.entry ?? []) {\n      for (const change of entry.changes ?? []) {\n        await this.applyInstagramChange(change)\n      }\n    }\n    response.status(200).send('EVENT_RECEIVED')\n  }","sourceCodeStart":23,"sourceCodeEnd":59,"githubUrl":"https://github.com/yikart/AiToEarn/blob/d3aa8bea5b146a8675607cf0144d891aad3e9683/project/aitoearn-backend/apps/aitoearn-server/src/core/channels/platforms/instagram/instagram-webhook.provider.ts#L23-L59","documentation":"Instagram webhook provider rejects POST notifications whose X-Hub-Signature-256 header does not match an HMAC-SHA256 computed from the raw request body using the app's client secret. The provider responds 401 with a localized ChannelWebhookInvalidSignature message and drops the payload. This guards against spoofed or tampered Meta webhook events.","triggerScenarios":"POST to the Instagram webhook endpoint with a missing, malformed (not 'sha256=' prefixed), or mismatched x-hub-signature-256 header; or when config.clientSecret is unset so verification always fails.","commonSituations":"Wrong or rotated Meta app secret in env (INSTAGRAM_CLIENT_SECRET); a proxy/gateway re-encoding the body so the signature no longer matches raw bytes; missing rawBody due to body-parser ordering; traffic not actually from Meta (scanners probing the endpoint).","solutions":["Verify the configured client secret matches the Meta app that subscribed the webhook","Ensure the framework preserves request.rawBody for this route (raw-body middleware before JSON parsing)","Check that no intermediary (proxy, WAF) modifies the request body or strips the signature header","Retry the webhook subscription from Meta App Dashboard to resend with a valid signature"],"exampleFix":"// before\n InstagramModule.forRoot({ clientSecret: process.env.META_APP_ID_SECRET_DEV })\n// after\n InstagramModule.forRoot({ clientSecret: process.env.META_APP_SECRET }) // correct app secret for the subscribed app","handlingStrategy":"validation","validationCode":"const sig = req.headers['x-hub-signature-256']\nif (!sig?.startsWith('sha256=')) throw new Error('missing Instagram signature')\nconst expected = 'sha256=' + createHmac('sha256', process.env.META_APP_SECRET).update(rawBody).digest('hex')\nif (!timingSafeEqual(Buffer.from(expected), Buffer.from(sig))) throw new Error('signature mismatch')","typeGuard":"function hasValidIgSignature(sig: unknown): sig is string {\n  return typeof sig === 'string' && sig.startsWith('sha256=')\n}","tryCatchPattern":null,"preventionTips":["Keep META_APP_SECRET in sync with the Meta app sending webhooks","Always capture rawBody before JSON parsing","Never proxy webhook bodies through re-serializing middleware","Use constant-time comparison for signatures"],"tags":["webhook","signature","instagram","security"],"backgroundTag":"webhook-signature-verification-failed","analyzedSha":"d3aa8bea5b146a8675607cf0144d891aad3e9683","analyzedAt":"2026-08-31T14:19:24.185Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}