PT-2026-53136 · Pypi · Praisonai

Published

2026-06-18

·

Updated

2026-06-18

CVSS v3.1

8.6

High

VectorAV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:L

PraisonAI LinearBot processes unsigned webhooks when LINEAR WEBHOOK SECRET is missing

Summary

PraisonAI's LinearBot starts a public webhook listener on 0.0.0.0 and treats LINEAR WEBHOOK SECRET as optional. When the secret is absent, startup only logs a warning and handle webhook() skips Linear-Signature verification entirely.
An unauthenticated network caller who can reach the webhook endpoint can submit a forged Linear-Event: AgentSession request. The forged request is parsed, scheduled for background processing, dispatched to handle agent session(), and passed into BotSessionManager.chat(). The bot then attempts to post the agent response back to Linear under the configured bot token.
The local PoV is offline and deterministic. It does not contact Linear. It calls the webhook handler directly, monkey-patches the outbound Linear comment path, and proves both sides of the boundary:
  • no secret configured: unsigned forged webhook returns 200, invokes the agent session path once, and attempts one Linear comment;
  • secret configured: missing and bad signatures both return 401 and do not invoke the agent;
  • secret configured with valid HMAC: request returns 200 and invokes the agent, proving the control path still works.

Affected Product

  • Repository: MervinPraison/PraisonAI
  • Package: praisonai
  • Components:
  • src/praisonai/praisonai/bots/linear.py
  • src/praisonai/praisonai/cli/features/bots cli.py
Validated affected:
  • live main / latest observed release v4.6.58: 1ad58ca02975ff1398efeda694ea2ab78f20cf3e
  • previous local current checkout: 2f9677abb2ea68eab864ee8b6a828fd0141612e1
  • v4.6.57
  • v4.6.56
  • v4.5.50
Sampled tags where the LinearBot component was not present:
  • v4.5.49
  • v4.5.51
  • v4.6.9
  • v4.6.10
Suggested affected range: LinearBot-bearing releases with the fail-open signature behavior, at least 4.5.50 and >= 4.6.56, <= 4.6.58. The component appears non-contiguously in sampled tags, so maintainers should confirm the exact packaged version history before publishing a final range.

Root Cause

LinearBot. init () accepts an empty signing secret and falls back to an empty environment value:
python
self. signing secret = signing secret or os.environ.get("LINEAR WEBHOOK SECRET", "")
start() treats the missing secret as a warning instead of refusing to expose the webhook listener:
python
if not self. signing secret:
  logger.warning("LINEAR WEBHOOK SECRET not set - webhook signatures will not be verified")

self. site = web.TCPSite(self. runner, "0.0.0.0", self. webhook port)
handle webhook() only verifies the request if the secret is truthy:
python
if self. signing secret:
  signature = request.headers.get("Linear-Signature", "")
  if not self. verify signature(raw body, signature):
    return web.Response(status=401, text="Invalid signature")
With no secret configured, the code continues to JSON parsing, accepts a caller supplied webhookTimestamp, reads the caller supplied Linear-Event header, and schedules processing:
python
event type = request.headers.get("Linear-Event", "")
task = asyncio.create task(self. process webhook(event type, body))
return web.Response(status=200, text="OK")
For AgentSession, the forged body is routed to the agent:
python
if event type == "AgentSession":
  await self. handle agent session(body)
...
response = await self. session mgr.chat(self. agent, user id, message.content)
await self. send comment(...)
The CLI has the same fail-open posture: start linear() loads LINEAR WEBHOOK SECRET, prints a warning when it is missing, then reports a public http://0.0.0.0:<port>/webhook endpoint with verification disabled.

Why This Is Not Intended Behavior

PraisonAI's Linear Bot documentation tells operators to set LINEAR WEBHOOK SECRET, pass it to praisonai bot linear, copy the Linear webhook signing secret, and use it for HMAC-SHA256 verification. The same page says missing secrets disable signature verification, while its best-practices section says webhook secrets ensure authenticity.
Linear's webhook documentation says receivers should ensure requests were sent by Linear by verifying the Linear-Signature HMAC over the raw body, then checking that webhookTimestamp is recent. The timestamp check alone is not an authentication boundary because an attacker can supply a current timestamp in a forged body.
The implementation itself also confirms the intended boundary: when a secret is configured, missing and bad signatures are rejected before agent dispatch. The bug is the missing-secret fail-open mode on a public webhook server, not the signature algorithm.

Local PoV

Run against the latest observed release checkout:
bash
python3 submission-bundle/praisonai-prai-cand-013-linear-webhook-signature-fail-open/poc/pov prai cand 013 linear webhook signature fail open.py --repo artifacts/repos/praisonai-v4.6.58
Expected output includes:
json
{
 "candidate": "PRAI-CAND-013",
 "ok": true,
 "cases": {
  "no secret unsigned forged webhook": {
   "http status": 200,
   "signing secret configured": false,
   "session calls": [
    {
     "user id": "linear-system",
     "content": "Issue: Forged Linear AgentSession event

PRAI-CAND-013 local forged webhook payload"
    }
   ],
   "sent comments": [
    {
     "issue id": "issue-prai-cand-013",
     "comment": "agent response",
     "session id": "prai-cand-013-session"
    }
   ]
  },
  "secret missing signature control": {
   "http status": 401,
   "session calls": []
  },
  "secret bad signature control": {
   "http status": 401,
   "session calls": []
  },
  "secret valid signature control": {
   "http status": 200,
   "session calls": [
    {
     "user id": "linear-system"
    }
   ]
  }
 }
}
Stored evidence:
  • evidence/pov-v4.6.58.json
  • evidence/pov-live-main-v4.6.58.json
  • evidence/pov-current-head.json
  • evidence/version-sweep.tsv

Impact

If a PraisonAI operator starts LinearBot with a Linear token but omits LINEAR WEBHOOK SECRET, any network caller that can reach the webhook endpoint can spoof Linear webhook events and invoke the configured agent through the Linear integration.
For the AgentSession event path, this lets the attacker supply issue title and description content that becomes the agent input. Depending on the configured agent and tools, this can cause unauthorized LLM/tool execution, consume paid model quota, create or update Linear comments under the bot identity, and drive the bot into workflows intended only for authenticated Linear events.
This report does not claim arbitrary code execution by default. The concrete boundary crossed is unauthenticated remote agent invocation through a forged Linear webhook.

Suggested Fix

Fail closed for public webhook listeners:
  1. Refuse to start LinearBot when LINEAR WEBHOOK SECRET is missing, unless an explicit development-only option such as --insecure-skip-webhook-signature-verification is provided.
  2. In handle webhook(), reject requests when no signing secret is configured instead of silently skipping verification.
  3. Preserve raw-body HMAC verification and constant-time comparison for the configured-secret path.
  4. Treat timestamp freshness as replay protection after signature validation, not as a replacement for authentication.
  5. Prefer loopback binding by default, or require an explicit host flag for public binding.
  6. Add regression tests:
  • no signing secret rejects startup or rejects webhook requests;
  • missing signature with a configured secret returns 401;
  • invalid signature with a configured secret returns 401;
  • valid HMAC with a configured secret returns success;
  • stale timestamp after valid HMAC returns 401;
  • the CLI does not advertise a public unauthenticated webhook by default.

Fix

Improper Authentication

Missing Authentication

Improper Verification of Cryptographic Signature

Found an issue in the description? Have something to add? Feel free to write us 👾

Weakness Enumeration

Related Identifiers

GHSA-FC26-M9PF-V56Q

Affected Products

Praisonai