Skip to content

ListStreams accepts a table ARN in TableName; the service refuses it #796

Open

Description

@LeeroyHannigan

What DynamoDB does

Measured 2026-11-03 in us-east-1. ListStreams with TableName set to a table ARN, arn:aws:dynamodb:us-east-1:<account>:table/<T>:

Caller Account in the ARN Answer
an admin another account that exists ValidationException "TableName must be at least 3 characters long and at most 255 characters long"
an admin an account that does not exist the same
no policy another account that exists the same
no policy an account that does not exist the same
no policy the caller's account the same

The ARNs sent were 54 to 57 characters long. The admin did not send an ARN in its own account.

What ExtendDB does

The same requests were replayed on 2026-11-03 against a SQLite server built from e3b0f96 (the head of #509):

Caller Account in the ARN Answer
a user allowed dynamodb:* on * another account in the catalog 200
a user allowed dynamodb:* on * an account not in the catalog 200
no policy another account in the catalog AccessDeniedException "User: is not authorized to perform: dynamodb:ListStreams on resource: arn:aws:dynamodb:us-east-1::table//stream/* because no identity-based policy allows the dynamodb:ListStreams action"
no policy an account not in the catalog the same
no policy the caller's account the same

The denial names <T> in the caller's account whichever account the ARN names.

Code path

The lines below are at main 03baa32; #509 does not change them.

  • authz_targets reduces a table ARN in TableName to its table name with table_name_only and authorizes table/<T>/stream/* in this deployment's account (crates/server/src/authz_resource.rs:494-507 and :626-633). Nothing checks the field before the IAM decision.
  • handle_list_streams passes TableName to the storage list_streams as written (crates/engine/src/streams.rs:48-72, the value at :60). SQLite compares it with the stored table names (crates/storage-sqlite/src/stream.rs:317-328), so an ARN matches no table and the list is empty. The replay recorded the status only; the empty list is read from the code.
  • fix(server): name the supplied ARN in a denial #509 leaves ListStreams out of its cross-account refusal, because the service reads this field as a name (find in crates/server/src/authz_resource/cross_account.rs).

Expected

A TableName that is a table ARN gets ValidationException "TableName must be at least 3 characters long and at most 255 characters long" before the IAM decision, for both callers. The service's answer for other values outside the table name pattern was not measured.

Related

#442 and #631 cover operations where the service accepts a table ARN in TableName. On ListStreams the service refuses one, so a shared resolution of table ARNs in TableName has to leave this field out.

Activity

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

Metadata

Metadata

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