Skip to content

TagResource and ListTagsOfResource accept a stream ARN for a stream that does not exist #452

Open

Description

@LeeroyHannigan

What ExtendDB does

validate_resource_arn in crates/engine/src/tagging.rs checks only that the table named in a stream ARN exists. TagResource on table/<name>/stream/<label> succeeds for a label the table never had and stores the tags under that ARN, and ListTagsOfResource returns them. ListTagsOfResource on table/<name>/stream/* returns 200.

What DynamoDB does

Measured on 2026-10-22: TagResource and ListTagsOfResource on a stream ARN with a label the table never had return ResourceNotFoundException "Requested resource not found: ResourceArn: not found". On table/<name>/stream/* and table/*/stream/<label> they return ValidationException "Invalid StreamArn".

Effect

Tags can be stored and listed for a stream that does not exist. DynamoDB does not evaluate stream tags for authorization, and with #419 ExtendDB does not either, so no IAM decision depends on them.

Suggested fix

Resolve the label against the table's streams before storing or listing tags. Return ResourceNotFoundException with the service's message for an unknown label, and ValidationException "Invalid StreamArn" for a wildcard table name or label. The answer for a disabled stream's label was not measured.

Activity

  1. LeeroyHannigan commented on Oct 31, 2026

    @LeeroyHannigan
    CollaboratorAuthor

    Two more cases from the same check, measured on a SQLite server built from main at 1d0d8f4, region us-east-1, a principal allowed dynamodb:* on *. Table tagrows-3a565fd5 with a stream, LatestStreamArn .../table/tagrows-3a565fd5/stream/2026-10-31T11:28:11.847.

    1. The check also accepts the issued stream ARN with a trailing space. TagResource on .../stream/2026-10-31T11:28:11.847 with k=trailing space: 200. ListTagsOfResource on that spelling: 200, that tag, as its own row beside the issued ARN's. The service answer for this spelling was not measured. An exact label compare refuses it together with the unknown label.

    2. The rows outlive the table and come back on a new table of the same name. TagResource on .../stream/2000-01-01T00:00:00.000 with k=unknown label: 200. DeleteTable, then wait until DescribeTable answers ResourceNotFoundException: the tags table still holds that row, the trailing-space row and the issued ARN's row. CreateTable with the same name (new label 2026-10-31T11:28:12.956), then ListTagsOfResource on the unknown-label ARN from before the delete: 200, k=unknown label. DeleteTable again: all three rows are still there.

    DeleteTable deletes only the rows whose resource_arn is the table ARN, on all four backends (storage-sqlite/src/delete_table.rs:118, storage-postgres/src/delete_table.rs:239 and :617, storage-cassandra/src/delete_table.rs:181, storage-mongodb/src/table_engine.rs:622; SQLite run, the other three read). Keeping the issued ARN's rows matches the service (#607). Rows under a label the table never had have no service counterpart, since the service refuses the write.

    So resolving the label, as suggested above, stops new rows and leaves the ones already written. The fix or the upgrade has to say what happens to those.

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

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