Skip to content

feat(decoder): expose the maximum nesting depth as a configuration option - #77

Merged
Spomky merged 1 commit into
3.1.xfrom
feat/decoder-max-depth-option-3.1.x
Aug 31, 2026
Merged

Spomky merged 1 commit into
3.1.xfrom
feat/decoder-max-depth-option-3.1.x

Conversation

@Spomky

@Spomky Spomky commented Aug 31, 2026

Copy link
Copy Markdown
Member

Targets the new 3.1.x branch, cut from 3.0.x: this adds a feature, so it does not belong on a patch branch.

What

spomky-labs/cbor-php 3.3.3 bounds how deeply nested a decoded data item may be — without it, a payload of a few dozen kilobytes made only of nested arrays builds an object graph deep enough to segfault the process when it is released, after decode() has already returned. The bundle now exposes that bound:

# config/packages/cbor.yaml
cbor:
    max_depth: 1000 # Default, CBOR\Decoder::DEFAULT_MAX_DEPTH

A much lower value is worth setting when the decoded data comes from an untrusted source:

cbor:
    max_depth: 32

How

The bundle had no configuration at all — getConfiguration() returned null. It now returns a Configuration with a single max_depth integer node (default Decoder::DEFAULT_MAX_DEPTH, minimum 1, info() filled in for config:dump-reference). The value lands in the cbor.max_depth container parameter and is passed to the Decoder service as its $maxDepth argument; the tag and other object managers keep being autowired, so nothing else about the service changes.

spomky-labs/cbor-php moves from ^3.0 to ^3.3.3, the release that introduces Decoder::DEFAULT_MAX_DEPTH.

The PHPStan baseline is regenerated: narrowing getConfiguration() to a non-nullable return type removes one of its entries.

Tests

tests/Functional/MaxDepthTest.php boots the test kernel with max_depth: 64 and checks the parameter value, that 64 levels decode, and that 65 are rejected with the exact message. Full suite: 32 tests, 35 assertions.

Verified locally in ghcr.io/spomky-labs/phpqa:8.4: PHPStan, ECS, Rector, parallel-lint, Deptrac, licenses, PHPUnit and Infection all pass.

…tion

spomky-labs/cbor-php 3.3.3 bounds how deeply nested a decoded data item may be,
so that a small payload of nested arrays can no longer build an object graph deep
enough to crash the process when it is released. That bound is now reachable from
the bundle configuration:

    cbor:
        max_depth: 1000 # CBOR\Decoder::DEFAULT_MAX_DEPTH

The value is passed to the Decoder service as its $maxDepth argument, while the
tag and other object managers keep being autowired. A much lower value is worth
setting when the decoded data comes from an untrusted source.
@Spomky Spomky self-assigned this Aug 31, 2026
@Spomky Spomky added this to the 3.1.0 milestone Aug 31, 2026
@Spomky Spomky added the enhancement New feature or request label Aug 31, 2026
@Spomky
Spomky merged commit f0705af into 3.1.x Aug 31, 2026
16 checks passed
@Spomky
Spomky deleted the feat/decoder-max-depth-option-3.1.x branch August 31, 2026 17:54
Spomky added a commit that referenced this pull request Sep 12, 2026
…php 3.4 registry (#84)

* feat(decoder): expose the maximum nesting depth as a configuration option (#77)

spomky-labs/cbor-php 3.3.3 bounds how deeply nested a decoded data item may be,
so that a small payload of nested arrays can no longer build an object graph deep
enough to crash the process when it is released. That bound is now reachable from
the bundle configuration:

    cbor:
        max_depth: 1000 # CBOR\Decoder::DEFAULT_MAX_DEPTH

The value is passed to the Decoder service as its $maxDepth argument, while the
tag and other object managers keep being autowired. A much lower value is worth
setting when the decoded data comes from an untrusted source.

* feat(decoder): build the tag and other object managers from the cbor-php 3.4 registry

cbor-php 3.4.0 implements the 58 tags of the IANA registry that used to fall
through to GenericTag, and files them in its decoder through the new
TagManager::register(), which names a class without loading it.

The bundle did not benefit from any of it: the TagManager and
OtherObjectManager services it declared were never injected into the Decoder
(the compiled container read "new Decoder(null, null, 64)"), and the two
compiler passes looked for a definition of the *interface*, which nothing
declared, so the documented "cbor.tag" and "cbor.other_object" service tags
were no-ops. Had they run, they would have handed service *instances* to
add(), which takes a class name -- and a tag class, whose constructor takes
the decoded data, is not something the container can build anyway.

The managers are now built by two factories that carry the registry the
library keeps private (a test compares them by reflection so the copy cannot
fall behind), and are injected into the Decoder and aliased by their
interfaces. An application registers its own classes by name, three ways:
the new "tags" / "other_objects" configuration keys, the service tags, or
the autoconfiguration of the interfaces. The passes only take the class of a
tagged definition, compute the tag number at compile time and file it with
register(); the container never instantiates the service, and a class that
does not implement the interface is refused with a message naming it.

The COSE messages of the appendices of RFC 8152 and RFC 8392, as published
by the IETF COSE working group (public domain), are decoded by the bundle's
decoder into the library's COSE tag classes and written back byte for byte.

* fix(releases): update minor release support matrix for versions 3.1.x and 3.0.x

* fix(di): declare the manager factories as arrays, which Symfony 6.4 understands

ServiceConfigurator::factory() only takes a Closure since Symfony 7.1; the
first-class callable Rector wrote broke the container on the 6.4 version this
branch supports. The rule is skipped on the service configuration.
Spomky added a commit that referenced this pull request Sep 12, 2026
* origin/3.1.x:
  feat(decoder): expose the maximum nesting depth as a configuration option (#77)

# Conflicts:
#	.ci-tools/phpstan-baseline.neon
#	README.md
#	composer.json
#	src/DependencyInjection/SpomkyLabsCborExtension.php
#	src/Resources/config/services.php
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant