This package is part of a large family (100+ identified as of September 2026) of near-identical
forks of the Baileys WhatsApp Web library that inject a covert channel-subscription action into
the WhatsApp socket layer. On connect, the injected code issues an authenticated `w:mex` FOLLOW
query (query_id 7871414976211147) against one or more attacker-chosen WhatsApp Channel/Newsletter
JIDs, using the installer's own authenticated WhatsApp session -- silently subscribing the
victim's account to channels it never asked to join.
The target JID(s) are hidden from casual source review via one of several obfuscation techniques
observed across the family: a plain string literal, base64 encoding, base64+XOR, or a char-code
array reconstructed at runtime. Some variants instead fetch a mutable, attacker-controlled remote
JSON/JS list of target JIDs from GitHub or another host at runtime, letting the target list change
after installation without a new npm publish. Every sample in the family shares the same underlying
mechanism (a wrapped/patched socket-connect routine that fires the FOLLOW query some seconds after
connect), even though the package name, JID value(s), and obfuscation/delivery method differ per
fork.
The malicious action abuses the installer's own authenticated WhatsApp session to gain reach and
subscribers for attacker-controlled channels; it does not exfiltrate credentials, establish
persistence, or execute arbitrary remote code.
Affected package: @bottino/baileys (npm), version(s): 1.0.14, 1.0.13, 1.0.12, 1.0.11, 1.0.10, 1.0.9, 1.0.8, 1.0.7, 1.0.6, 1.0.5, 1.0.2, 1.0.1.
---
_-= Per source details. Do not edit below this line.=-_
## Source: amazon-inspector (571d52cf3274d95d4824667269921b2e0ad1478fe9f324a74fab0ba377bb9a26)
This fork of Baileys overrides `requestPairingCode` so that when the caller does not supply an explicit `pairKey`, `authState.creds.pairingCode` is set to the fixed literal string `BYPAKI64`. That value is then used as the KDF input for the WhatsApp companion-device link-code encryption via `derivePairingCodeKey(authState.creds.pairingCode, salt)`. Because the pairing code is a known constant baked into the package, anyone who knows the target phone number of the installer's WhatsApp account can complete the companion-device pair flow from a device they control and obtain persistent access to the installer's WhatsApp session (read/send messages, contacts, media) — a full account takeover backdoor against any application built on this library. Additionally, on socket connect the code auto-subscribes the installer's WhatsApp account to a hardcoded newsletter JID `120363418582531215@newsletter` and persists a `basedbysam` flag so the covert subscribe runs once per credential store; this covert action uses the installer's WhatsApp identity without disclosure.
CVE-2026-97273 is a high-severity unauthenticated cross-site scripting (XSS) vulnerability in Premmerce Wishlist for WooCommerce versions up to 1.1.13. This flaw involves improper neutralization of input during web page generation, allowing an attacker to inject malicious scripts. The vulnerability requires no privileges but user interaction is needed to trigger the exploit. It affects confidentiality, integrity, and availability of the affected system.
CVE-2026-103345 is a medium severity vulnerability in Shamim Rajani's Pie Register plugin that allows insertion of sensitive information into sent data, potentially exposing embedded sensitive data. It affects versions from initial releases up to 3.8.4.13 inclusive.
## Summary
`HTTPServerRequest.__init__` in `tornado/httputil.py` parses the URL query string via
`parse_qs_bytes()` with no field-count limit — while the sibling POST-body parsing path
(`parse_body_arguments`) received a `max_num_fields=1000` cap added earlier in this exact
same release (v6.5.8, commit `8d6363ed`), explicitly to bound parsing cost for the identical
underlying primitive. This leaves the query-string path with the resource-exhaustion exposure
the body-path fix was meant to close.
**File**: `tornado/httputil.py`, line 553 (`HTTPServerRequest.__init__`)
### Root Cause
```python
# tornado/httputil.py:553 (before fix)
self.arguments = parse_qs_bytes(self.query, keep_blank_values=True)
```
Compare with the POST-body path fixed one commit earlier in the same release:
```python
# tornado/httputil.py:1038-1041
uri_arguments = parse_qs_bytes(
body,
keep_blank_values=True,
max_num_fields=config.urlencoded.max_arguments, # default 1000
)
```
Both call sites funnel through the same `tornado.escape.parse_qs_bytes` (a thin wrapper over
`urllib.parse.parse_qs`), which is exactly why `max_num_fields` was added to
`urllib.parse.parse_qsl` upstream — to let frameworks bound field count. The fix was applied
only to the body path; the query-string path was missed.
The request line + headers together are capped at `max_header_size` (default 65536 bytes), so
this is not literally unbounded, but a single ~64KB request line can carry thousands of short
`key=value` pairs — far beyond the 1000-field limit the maintainer judged appropriate for the
structurally identical body case.
### Attack Scenario
1. Attacker sends a `GET` request whose query string is packed with thousands of short fields
(e.g. `k0=1&k1=1&...&k7799=1`, ~61KB), fitting comfortably under `max_header_size`. No
authentication, cookies, or prior state required.
2. Tornado accepts and parses this with no field-count cap, unlike the equivalent POST-body
request (which is correctly rejected with 400 once >1000 fields are present).
3. Parsing thousands of fields is CPU work performed synchronously inside Tornado's
single-threaded `IOLoop`. Several such requests in flight concurrently stall the event
loop, delaying processing of *all* other connections on that loop — not just the
attacker's own request.
### Verification (dynamic, local reproduction against v6.5.8)
Ran the unmodified v6.5.8 source directly (no external dependencies needed) with a minimal
`tornado.web.Application` on `127.0.0.1:8888`.
- Identical 7800-field/~61KB payload sent as GET query string → `200 OK`; sent as POST body
(`application/x-www-form-urlencoded`) → `400 Bad Request` (correctly rejected by the
existing `max_num_fields` body-path limit). This confirms the asymmetry directly.
- Per-request parse cost: baseline (`/?a=1`) averaged 1.86ms; the 7800-field query string
averaged 25.1ms (~13x).
- Event-loop-blocking amplification (raw-socket test, isolating server-side stall from
client overhead): with 10 sequential baseline probe requests fired with no load, average
latency was 1.47ms (max 5.9ms). With 5 concurrent 61KB/7800-field requests in flight,
the same baseline probes averaged 13.0ms (max 118.1ms) — an **8.9x average slowdown** for
unrelated clients, produced by ~305KB of unauthenticated attacker traffic.
### Impact
All Tornado servers/applications are affected — this triggers on every request with a query
string, independent of application/handler logic. An unauthenticated, unprivileged remote
attacker can measurably degrade response times for all other clients sharing the same
`IOLoop`, using a small amount of bandwidth and no special conditions. This is an
availability/DoS concern; no confidentiality or integrity impact.
### Recommended Fix
```python
# tornado/httputil.py — HTTPServerRequest.__init__
if uri is not None:
self.path, sep, self.query = uri.partition("?")
try:
self.arguments = parse_qs_bytes(
self.query,
keep_blank_values=True,
max_num_fields=_DEFAULT_PARSE_BODY_CONFIG.urlencoded.max_arguments,
)
except ValueError as e:
raise HTTPInputError("Invalid query string: %s" % e) from e
```
This reuses the existing `ParseUrlEncodedConfig.max_arguments` default (1000) via the
module's `_DEFAULT_PARSE_BODY_CONFIG`, matching the POST-body limit and honoring any global
override via `set_parse_body_config()`. The `try/except` is necessary because — unlike
`parse_body_arguments`, which already wraps its call and converts `ValueError` into a clean
`HTTPInputError`/400 — the query-string call site currently has no such handling, so without
it, a request exceeding the limit would raise an uncaught `ValueError` instead of a clean 400.
Verified: with the fix applied, requests with ≤1000 query-string fields are unaffected;
requests with >1000 fields are rejected with `400 Bad Request` (consistent with the POST-body
behavior); Tornado's own `httputil_test` and `web_test` suites (256
PyJWT versions 2.11.0 through 2.13.0 contain a vulnerability where the decode() and decode_complete() functions mutate a caller-supplied options dictionary when signature verification is disabled. This mutation can cause subsequent calls that enable signature verification to inherit disabled claim checks such as expiration, audience, issuer, and subject verification, allowing acceptance of tokens with invalid claims without raising exceptions. This is a claims verification bypass, not a signature verification bypass. The issue is a regression introduced in March 2025 by a refactor that removed a shallow copy of the options dictionary. The vulnerability requires the application to reuse the same mutable options dictionary across decode calls with different verification intents.
### Summary
GitPython's `Actor.name_email_regex` regular expression (`git/util.py`, line 863)
is vulnerable to catastrophic backtracking (ReDoS — Regular Expression Denial of
Service). When GitPython parses the `author` or `committer` header of a git commit
object that contains a long string with an unterminated `<` (no matching `>`), the
Python regex engine enters quadratic backtracking, causing complete single-threaded
CPU exhaustion proportional to the square of the input length.
A single crafted commit object can block any GitPython API call that reads
`.author` or `.committer` for **over two minutes per invocation**, enabling denial
of service against CI runners, code-hosting backends, repository-scanning
pipelines, or any service that processes commits from third-party or untrusted
repositories.
---
### Details
**Vulnerable file and line:**
`git/util.py`, line 863:
```python
name_email_regex = re.compile(r"(.*) <(.*?)>")
```
This regex is evaluated inside `Actor._from_string()` (line 909) every time
GitPython resolves a commit's `.author` or `.committer` property.
**Full call chain — from public API to vulnerable sink:**
commit.author # any ordinary GitPython API call
└── git/objects/commit.py:917
Commit._deserialize()
└── git/objects/util.py:341
parse_actor_and_date(author_line)
└── git/util.py:909
Actor._from_string(string)
└── Actor.name_email_regex.search(string) ← VULNERABLE
`author_line` is decoded directly from the raw bytes of the git commit object with
**no length limit, character restriction, or timeout** applied at any point before
reaching the regex engine. The same chain is triggered by:
- `commit.author`
- `commit.committer`
- `repo.iter_commits()`
- `repo.blame()`
- Any web service / CI tool that displays or processes commit metadata
**Why this pattern backtracks catastrophically:**
The pattern `(.*) <(.*?)>` contains an unbounded greedy group `(.*)` followed by
a literal space and `<`. When the input is a long string that contains `<` but no
closing `>`, the regex engine must try every possible split position for the greedy
group — O(n²) candidate positions for a string of length n — each of which then
drives the inner lazy group into further sub-match attempts. This is the
well-documented "catastrophic backtracking" failure mode for this family of
patterns.
**Empirically measured scaling (tested against GitPython 3.1.59, commit 52a6cba):**
| Author field length (bytes) | Time to resolve `.author` |
|-----------------------------|--------------------------|
| 1,000 | 0.0035 s |
| 5,000 | 0.084 s |
| 10,000 | 0.341 s |
| 20,000 | 1.525 s |
| 40,000 | 5.963 s |
| 60,000 | 13.360 s |
| 80,000 | 23.871 s |
| **200,000** | **150.488 s** |
Each doubling of input size roughly quadruples processing time (e.g. 40,000 →
80,000 bytes: 5.96 s → 23.87 s ≈ 4.0×), confirming O(n²) growth. Git itself
imposes **no practical size limit** on author name fields in the object format.
**How the malicious object reaches a victim:**
The PoC creates the commit object as a correctly SHA-1-hashed, zlib-compressed git
loose object written directly into `.git/objects/`. `git cat-file -t <sha>` confirms
it is a valid `commit` type and git's own read-side tools display it without error.
Only git's write-side tooling (`git commit --author`, `git update-index`,
explicit `git fsck`) applies the sanity checks that would reject a malformed author
line. Delivery paths that bypass those checks include:
- A git server with `receive.fsckObjects = false` (common in self-hosted deployments)
- A `.git` directory shipped as a tarball, backup, or zip archive
- A git bundle file
- Any automated mirror or import tool that operates at the object level
---
### PoC
**Environment used for testing:**
- GitPython 3.1.59, installed in editable mode from source (no code modifications)
- Python 3.12.3, git 2.43.0, Ubuntu 24.04
**Script 1 — craft the malicious repository (`craft_malicious_repo.py`):**
```python
#!/usr/bin/env python3
"""
Creates a git repository with one commit whose 'author' field is a large
string containing an unterminated '<'. Bypasses git's write-side sanity
checks by writing the raw object directly into .git/objects/.
Usage: python3 craft_malicious_repo.py <target_dir> <payload_size_bytes>
"""
import hashlib, os, subprocess, sys, zlib
def run(cmd, cwd):
return subprocess.run(cmd, cwd=cwd, check=True, capture_output=True, text=True)
def main():
if len(sys.argv) != 3:
print(f"usage: {sys.argv[0]} <target_dir> <payload_size_bytes>")
sys.exit(1)
target_dir, payload_size = sys.argv[1], int(sys.argv[2])
os.makedirs(target_dir, exist_ok=True)
run(["git", "init", "--quiet"], cwd=target_dir)
run(["git", "config", "user.email", "poc@example.com"], cwd=target_dir)
run(["git", "config", "user.name", "PoC"], cwd=target_dir)
with open(os.path.join(target_dir, "README.txt"), "w") as f:
f.write("GitPython ReDoS PoC repository\n")
run(
CloudTAK is a browser-based Common Operating Picture and situational awareness tool compatible with TAK. Prior to version 13.10.0, every route in the ESRI helper family (api/routes/esri.ts) takes a fully attacker-controlled URL from the request (POST /api/esri body url, and the portal / server / layer query parameters on the GET /api/esri/* routes) and passes it into EsriBase / EsriProxyPortal / EsriProxyServer / EsriProxyLayer in api/lib/esri.ts, which fetch it with the bare fetch from @tak-ps/etl. No IP / DNS / hostname classification is applied at any point, so the destination is never validated against private, loopback, or link-local ranges. Any authenticated user (the routes only require Auth.is_auth(config, req, { anyResources: true }), i.e. any token, not an admin) can therefore make the CloudTAK server issue arbitrary outbound GET/POST requests to internal addresses such as the cloud instance-metadata service (169.254.169.254), loopback admin ports (127.0.0.1:<port>), and other hosts reachable only from inside the deployment VPC. This is a full-read SSRF, not blind: on success the upstream JSON body is returned to the caller via res.json(...), and on failure the upstream error string is reflected verbatim as ESRI Server Error: <message>. An attacker can read cloud metadata (and the temporary IAM credentials the instance role exposes), enumerate internal services, and exfiltrate their response bodies. The sniff() URL classifier provides no protection: it only pattern-matches the pathname (/rest, /arcgis/rest, /sharing/rest), so a URL like http://169.254.169.254/arcgis/rest or http://127.0.0.1:8500/rest passes sniff() and is fetched. This issue has been patched in version 13.10.0.
WatchGuard released patches for 15 vulnerabilities in Fireware OS, including a critical remote code execution (RCE) vulnerability (CVE-2026-86131) involving code injection via BOVPN over TLS client configurations. Exploitation could allow remote attackers controlling a VPN server to execute commands with root privileges on Firebox appliances. The update also addresses 13 other high-severity issues such as RCE, authorization bypass, denial-of-service, unauthorized SSLVPN access, and arbitrary local file reads, plus a medium-severity improper authorization flaw. Additional critical and high-severity vulnerabilities affecting WatchGuard Access Points were patched in version 3.4.8. No exploitation in the wild is currently known.
An authenticated user can list alert rules stored in folders they are not allowed to read through the alert rules API list endpoint. When the set of folders the user may read was empty, the folder restriction was dropped and every alert rule in the organization was returned. From Grafana 13.1.0, any user can trigger this with a folder filter. The exposed data is rule configuration; data source credentials are not exposed.