sync: auto-sync from HOWARD-HOME at 2026-07-07 11:45:40
Author: Howard Enos Machine: HOWARD-HOME Timestamp: 2026-07-07 11:45:40
This commit is contained in:
@@ -138,6 +138,17 @@ rule = fleet-wide, gated by the metadata match). **Do NOT blanket-whitelist an R
|
||||
grandparent by itself** — the RMM is a SYSTEM-level RCE channel and the top MSP attack path;
|
||||
whitelisting all of it blinds EDR exactly where it matters.
|
||||
|
||||
**[DANGER] API create footgun (verified live 2026-07-07).** `POST /SuppressionRules` on this
|
||||
tenant (a) **ignores `active:false` and forces the rule LIVE immediately**, and (b) auto-creates
|
||||
an **EMPTY-metadata version that matches EVERYTHING**. So the two-step "create rule → then add
|
||||
version" path leaves a live match-all suppression window (observed ~2 min → deleted). Also note
|
||||
`GET`/`PATCH /SuppressionRules/{id}` (single-resource route) **HTTP 400** "undefined is not valid
|
||||
JSON" on this tenant — read via `GET /SuppressionRules?filter={"where":{"id":"..."}}` instead;
|
||||
**`DELETE /SuppressionRules/{id}` DOES work** (returns null, sets `deleted:true`). Until an
|
||||
**atomic** create (metadata embedded in the POST body) is verified, **create suppressions in the
|
||||
CONSOLE**, not via `raw POST`. If you must POST, verify the version's active fields IMMEDIATELY
|
||||
and `DELETE` on any doubt.
|
||||
|
||||
**Create — CONSOLE-observed, API create RUN-unverified.** Console flow: open the alert →
|
||||
**Create Suppression Rule** → check the desired Match fields → Save. This POSTs a
|
||||
`SuppressionRule` (carrying `alertId`, `name`, `description`, `organizationId`, `locationId`,
|
||||
|
||||
@@ -267,7 +267,7 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
sp.add_argument("method", help="GET/POST/PUT/DELETE")
|
||||
sp.add_argument("path", help="e.g. Agents or Agents/scan")
|
||||
sp.add_argument("--filter", help="LoopBack filter JSON (GET)")
|
||||
sp.add_argument("--data", help="request body JSON")
|
||||
sp.add_argument("--data", help="request body JSON, or @path to read JSON from a file")
|
||||
sp.add_argument("--confirm", action="store_true",
|
||||
help="required for non-GET methods")
|
||||
return p
|
||||
@@ -408,7 +408,13 @@ def main(argv=None) -> int:
|
||||
print(f"[BLOCKED] {method} requires --confirm.", file=sys.stderr)
|
||||
return 2
|
||||
filt = json.loads(args.filter) if args.filter else None
|
||||
body = json.loads(args.data) if args.data else None
|
||||
if args.data and args.data.startswith("@"):
|
||||
with open(args.data[1:], "r", encoding="utf-8") as _f:
|
||||
body = json.load(_f)
|
||||
elif args.data:
|
||||
body = json.loads(args.data)
|
||||
else:
|
||||
body = None
|
||||
# Same tenant-wide footgun guard the scan command has: a POST to any
|
||||
# */scan endpoint with no non-empty `where` scans the ENTIRE tenant.
|
||||
if method == "POST" and args.path.rstrip("/").lower().endswith("scan"):
|
||||
|
||||
Reference in New Issue
Block a user