Skip to content

Runtime hardening: input-handling defense in depth - #550

Closed
ludoch wants to merge 1 commit into
mainfrom
harden-deferred-task-and-xml
Closed

ludoch wants to merge 1 commit into
mainfrom
harden-deferred-task-and-xml

Conversation

@ludoch

@ludoch ludoch commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator

What

Defense-in-depth hardening of input handling in the runtime:

  1. Deferred-task servlet (DeferredTaskServlet, both javax and jakarta
    variants): apply an ObjectInputFilter when reading the task payload, with a
    default blocklist overridable via the appengine.deferredtask.serialFilter
    system property and merged with any JVM-wide jdk.serialFilter. Legitimate
    DeferredTask payloads are unaffected.

  2. XML config parsing (XmlUtils and AppEngineWebXmlInitialParse): disable
    DTDs / external entities / external DTD and schema access when parsing
    appengine-web.xml, queue.xml, cron.xml, dos.xml, etc.

Testing

New unit tests for both changes; existing DeferredTaskServletTest (11) and
AppEngineWebXmlInitialParseTest (37) pass. Verified end-to-end on App Engine
that deferred tasks and push task-queue delivery continue to work with the
change in place.

Rationale and detailed verification shared separately.

🤖 Generated with Claude Code

DeferredTaskServlet (both javax and jakarta variants) deserialized the task
payload through a plain ObjectInputStream with no class filter. The endpoint is
registered in every app and its only guard is the X-AppEngine-QueueName header,
which the infrastructure attaches to every delivered Task Queue task. Anyone who
can create a task in the project (cloudtasks.tasks.create / taskqueue) can
therefore have an arbitrary serialized object graph of their choosing
deserialized in the app, which is remote code execution when an exploitable
gadget class is on the app classpath.

Add an ObjectInputFilter to readRequest():
 - a default blocklist of well-known deserialization-gadget packages
   (DEFAULT_SERIAL_FILTER), overridable via the appengine.deferredtask.serialFilter
   system property;
 - merged with any JVM-wide jdk.serialFilter so a class rejected by either is
   rejected.
Legitimate DeferredTask payloads are unaffected.

Also harden the XML config parsers against XXE: XmlUtils (DocumentBuilderFactory
and the schema Validator) and AppEngineWebXmlInitialParse (StAX) now disable
DTDs / external entities / external DTD and schema access. These parse
appengine-web.xml, queue.xml, cron.xml, dos.xml, etc.

Tested: new unit tests for the filter (blocked class rejected, normal class and
real DeferredTask allowed) and for XXE (external entity not resolved); existing
DeferredTaskServletTest (11) and AppEngineWebXmlInitialParseTest (37) still pass.
Verified live on App Engine (see PR): on a stock runtime the gadget payload is
fully deserialized (ClassCastException); on this patched runtime it is refused
(InvalidClassException: filter status: REJECTED) while normal deferred tasks and
push tasks keep working.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ludoch ludoch changed the title Harden deferred-task deserialization and XML config parsing Runtime hardening: input-handling defense in depth Oct 24, 2026
@google-cla

google-cla Bot commented Oct 24, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@ludoch ludoch closed this Oct 24, 2026
@ludoch
ludoch deleted the harden-deferred-task-and-xml branch October 24, 2026 13:56
@ludoch

ludoch commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

Superseded by #551 (same change; the branch was renamed, which closed this PR). Continuing there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant