Skip to content

Protected query-param check is trivially evaded by adding any title, and cannot express value thresholds (functional) #51

Description

@jeffw16

Requirement type: functional

Problem

The $wgCrawlerProtectedQueryParams mechanism added in response to #35 denies a request only when the protected parameter appears without a title:

$title = $request->getVal( 'title' );
if ( $title !== null && trim( $title ) !== '' ) {
	return false;
}

The reasoning in #35 is sound — MediaWiki never emits target= without title=, so the no-title shape is a reliable crawler fingerprint. But the mechanism being defended against is cache-busting via unbounded unique URLs, and adding &title=Main_Page to the same request restores the entire attack: still a unique URL per from= timestamp, still a full main-page render, still 0% cache hit rate, and now it sails past this check. The fingerprint was cheap to add and cheap to evade.

Related gaps in the same area:

  • Nothing constrains unknown or irrelevant query parameters generally. Any index.php?title=Main_Page&cachebust=<random> defeats CDN caching at zero cost to the attacker.
  • $wgCrawlerProtectedQueryParams matches on parameter presence only. There is no way to express "deny when limit exceeds N" or "deny when days exceeds N", which is where the actual cost lives — limit=5000&days=365 is expensive, limit=50&days=7 is not.

Proposals

  1. Extend the check so a protected parameter combined with a title that does not name the special page which consumes that parameter is also denied (e.g. target= alongside title=Main_Page). This preserves legitimate title=Special:WhatLinksHere&target=Foo links while closing the trivial evasion.
  2. Add value-threshold rules, e.g. $wgCrawlerProtectedQueryParamLimits = [ 'limit' => 500, 'days' => 30 ], denying anonymous requests that exceed them. This targets cost directly rather than shape, and would also mitigate the same attack arriving via a properly-titled URL.
  3. Investigate the canonical-redirect idea raised at the end of Special-page query parameters sent without a title bypass CrawlerProtectedSpecialPages #35: when index.php receives parameters that cannot affect the resolved output, issue a 301 to the canonical URL. This collapses the cache-busting entirely and is cheaper than either a render or a denial. It is a larger change and arguably belongs upstream, but it addresses the mechanism rather than one signature and is worth prototyping here first.
  4. Whichever approach is chosen, ship it behind config that defaults to today's behaviour, and add the dry-run/logging mode requested in the observability issue so operators can measure false positives before enforcing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions