sickn33/agentic-awesome-skills · critical
Invalid signature
Error message
Invalid signature
What it means
The decorator recomputed the expected HMAC over the raw request body with the configured app secret, and hmac.compare_digest found it different from the X-Hub-Signature-256 header. A mismatch means the bytes verified are not the bytes Meta signed, or the secret used for verification differs from the secret used for signing. The request is aborted with 401 before the Flask handler runs.
Source
Thrown at skills/whatsapp-cloud-api/assets/boilerplate/python/webhook_handler.py:39
Validar esta assinatura previne requests falsificados.
Usa hmac.compare_digest para comparacao constant-time (previne timing attacks).
"""
secret = app_secret or os.environ["APP_SECRET"]
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
signature = request.headers.get("X-Hub-Signature-256", "")
if not signature:
abort(401, "Missing signature header")
raw_body = request.get_data()
expected = "sha256=" + hmac.new(
secret.encode(), raw_body, hashlib.sha256
).hexdigest()
if not hmac.compare_digest(signature, expected):
abort(401, "Invalid signature")
return f(*args, **kwargs)
return decorated_function
return decorator
def verify_webhook(verify_token: str | None = None):
"""
Handle webhook verification (GET request from Meta).
Returns the challenge to confirm the webhook endpoint.
"""
token = verify_token or os.environ["VERIFY_TOKEN"]
mode = request.args.get("hub.mode")
req_token = request.args.get("hub.verify_token")
challenge = request.args.get("hub.challenge")View on GitHub (pinned to 58d857988f)
Solutions
- Compare the deployed app secret byte-for-byte with Meta App Dashboard > App Settings > Basic > App Secret
- Make the HMAC decorator the first thing to touch the request so get_data() returns the exact bytes Meta signed
- If the secret was recently rotated, redeploy all instances and confirm every environment uses the new value
Defensive patterns
Strategy: validation
Validate before calling
# In tests, sign the exact bytes you send
body = json.dumps(payload).encode()
sig = 'sha256=' + hmac.new(APP_SECRET.encode(), body, hashlib.sha256).hexdigest()
client.post('/webhook', data=body, headers={'X-Hub-Signature-256': sig}) Try / catch
try:
verify_signature(request)
except Exception:
# log body length and a secret fingerprint (never the secret) to diagnose mismatches
raise Prevention
- Keep one source of truth for the app secret (secret manager), never hand-copied .env files
- Never let body-parsing middleware run before signature verification
When it happens
Trigger: WHATSAPP_APP_SECRET in the environment differs from the Meta app's App Secret; the raw body was consumed or re-encoded by earlier middleware so request.get_data() returns altered bytes; signature computed over pretty-printed or re-serialized JSON instead of the exact payload; header mangled by an intermediary.
Common situations: App secret rotated in the Meta developer console but not redeployed; secret copied with trailing whitespace, quotes, or from the wrong app; a body-parsing hook decoding/re-encoding the stream before verification; multiple environments (test/prod) pointing at different Meta apps.
Related errors
AI-assisted analysis of sickn33/agentic-awesome-skills@58d857988f (2026-08-26).
Data as JSON: /api/errors/3571c9e371c0a506.
Report an issue: GitHub.