What's Changed
New Contributors
- @matuscongrady made their first contribution in #2164
[1.5.27] — 2026-10-13
Added
- API Gateway — failed SigV4 authentication answers through the gateway responses — under
AUTH=truea REST API invoke that failed authentication got the generic JSON error and ignored the API's gateway responses; a wrong secret, a skewed clock or a credential date other than the request date now answersINVALID_SIGNATURE(InvalidSignatureException), an expired sessionEXPIRED_TOKEN(ExpiredTokenException), and an unknown key or a malformedAuthorizationheaderDEFAULT_4XXwith the matchingx-amzn-ErrorType, 403 with{"message": ...}. Contributed by @iot-rocket. - Auth — the request time of a header-signed request is checked — under
AUTH=truea request signed with an IAM user or STS session key was served whatever its time; one signed more than 15 minutes (STS, IAM, SNS, SQS, DynamoDB, S3, ECR, RDS, ElastiCache) or 5 minutes (the default for other services) from the server clock answersSignatureDoesNotMatch/InvalidSignatureExceptionwith AWS'sSignature expiredorSignature not yet currentmessage,RequestTimeTooSkewedfrom S3 andAuthFailurefrom EC2. Contributed by @iot-rocket. - Auth — the session token of a header-signed request is checked — under
AUTH=truean STS session key sent without its token was accepted and now answers as an unknown key, and a wrong token, or a token with an IAM user key, answersInvalidClientTokenId(UnrecognizedClientExceptionfrom JSON services,InvalidToken400 from S3), as on AWS. Contributed by @iot-rocket. - Auth — header signatures are verified for IAM user and STS session keys — under
AUTH=truea request signed with such a key and the wrong secret, or changed after signing, was served; it now answersSignatureDoesNotMatch(or the service'sInvalidSignatureException), anAuthorizationheader without itsSignatureorSignedHeadersanswersIncompleteSignature(LambdaMissingAuthenticationTokenException, S3AuthorizationHeaderMalformed) and a credential date other than the request dateSignatureDoesNotMatch(S3AuthorizationHeaderMalformed), S3 unsigned, streaming and signed-chunk payloads are checked the same way, and the root key still accepts any secret. Contributed by @iot-rocket. - IoT — MQTT publish, subscribe and receive evaluate IoT policies under
AUTH=true— after the CONNECT a certificate session could publish, subscribe and receive on any topic; it now needsiot:Publishon the topic (andiot:RetainPublishfor a retained message or will),iot:Subscribeper topic filter andiot:Receiveper delivered message. A refused PUBLISH or SUBSCRIBE closes an MQTT 3.1.1 connection (disconnect reasonCLIENT_ERROR), MQTT 5 answers PUBACK 0x87, DISCONNECT 0x87 at QoS 0 (AUTH_ERROR) or 0x87 for the refused filter, which thesubscribedevent leaves out (no event when none is granted), a refused will refuses the CONNECT, and a message the subscriber may not receive is dropped. Contributed by @iot-rocket. - IoT — MQTT connections evaluate
iot:ConnectunderAUTH=true— a device certificate on the mTLS listener connected under any client id, with or without a policy; withAUTH=truethe CONNECT now needs an attached policy that allowsiot:Connectonclient/<client id>and none that denies it, with${iot:ClientId},${iot:Connection.Thing.ThingName},iot:Connection.Thing.IsAttachedand${iot:Certificate.Subject.CommonName}resolved. A refusal closes an MQTT 3.1.1 connection without a CONNACK, answers MQTT 5 with CONNACK 0x87 and publishes$aws/events/presence/connect_failed/{clientId}. Contributed by @iot-rocket. - IoT —
TagResource,UntagResourceandListTagsForResource— the three operations answeredUnsupported IoT path, so the tags the Create calls accept could not be read back. They now work on thing types, thing groups, policies, topic rules, jobs, job templates, CA certificates, provisioning templates and domain configurations with AWS's limits and errors, Create calls and CloudFormationTagswrite the same tags, and deleting a resource drops them. Contributed by @iot-rocket. - IoT — retained messages —
GetRetainedMessageandListRetainedMessagesanswered 501not yet implemented; they now return the broker's retained messages (newest first, paged bymaxResultsandnextToken, with the user properties of an MQTT 5 publish), and aPERSIST_STATE=1restart keeps each message'slastModifiedTimeand user properties. Contributed by @iot-rocket. - IoT —
ListJobExecutionsForJob—GET /jobs/{jobId}/thingsanswered 400Unsupported IoT path; it now lists every execution of the job, earlier ones of a rejoined thing included, most recently updated first, with thestatusfilter andmaxResults/nextTokenpaging. Contributed by @iot-rocket. - IoT —
DeleteJobExecution—DELETE /things/{thingName}/jobs/{jobId}/executionNumber/{executionNumber}answered 400Unsupported IoT path; it now deletes the execution (anIN_PROGRESSone only withforce), drops it from the job's lists and counts, completes the job when only finished executions are left, and publishes thedeletedjob execution event and the thing'sjobs/notifytopics; aCONTINUOUSjob's thing left with no execution gets none back until it leaves the group, which leaves aREMOVEDexecution 1. Contributed by @iot-rocket. - Cognito —
InboundFederationtrigger on SAML and OIDC sign-in —LambdaConfig.InboundFederationwas stored but never invoked; SAML and OIDC federated sign-in now call the Lambda withInboundFederation_ExternalProvider, the provider-prefixeduserNameand the IdP'ssamlResponseoridToken. A non-emptyuserAttributesToMapreplaces the IdP attributes beforeAttributeMapping,{}keeps them, and a failing or missing function fails the sign-in withUserLambdaValidationException. Contributed by @kjdev.
Fixed
- Step Functions — aws-sdk Parameters for JSON-protocol services take the wire names —
ecsandecrreceived an aws-sdk task's PascalCaseParametersas sent, so their handlers ignored them (describeClusterswithClustersdescribeddefault,describeRepositorieswithRepositoryNamesreturned every repository), andsfnandcloudwatchlogslowercased every key, map keys included, sotagResourcestoredTeam-Nameasteam-Name; the parameters are now renamed by the operation's input model, with map keys such as tag keys kept as written. Reported by @lucasmfraser. - Step Functions — aws-sdk results for JSON-protocol services keep the SDK's shape at every depth — only the result's top-level keys took the SDK's names, so nested members kept their wire casing (
Executions[].executionArn,SecretList[].ARN), timestamps stayed epoch numbers and absent members came back asnull; the result is now shaped by the service's output model: structure members renamed at every depth (DynamoDB'sBOOL,NULLandSSasBool,NulandSs), map keys such as attribute names and tag keys kept as sent, timestamps as ISO 8601 with milliseconds, and absent members left out. A leading acronym is now lowered in every aws-sdk result, including two-letter names and ones with digits (IDasId,EC2InstanceIdasEc2InstanceId,MD5OfMessageBodyasMd5OfMessageBody). Contributed by @lucasmfraser. - S3 —
s3:prefix,s3:delimiterands3:max-keysunderAUTH=true—ListObjects,ListObjectsV2andListObjectVersionsset none of the three condition keys, so aListBucketorListBucketVersionsgrant scoped by them, such asStringLikeons3:prefixfor one user's home folder, never matched and the listing answeredAccessDenied; they now carry the request'sprefix,delimiterandmax-keys, path-style and virtual-hosted. Reported by @bettiah. - Idle memory — the IoT mTLS listener built its TLS context at boot, which imported
cryptographyand minted the broker certificate before any device connected. It now binds port 8883 without TLS and builds the context on the first connection, andx509_utilsimportscryptographyon first use: an idle container drops from about 36.7 to 32.8 MiB. - Cognito — token lifetimes follow the app client — access and ID tokens,
ExpiresInand the/oauth2/tokenexpires_inwere always one hour; they now follow the client'sAccessTokenValidity,IdTokenValidityandTokenValidityUnits(one hour when unset, as on AWS), a client created without the two validities no longer reports60for them, and an expired token is refused by API Gateway's Cognito and JWT authorizers and, withAUTH=true, an expired access token by Cognito withAccess Token has expired. Contributed by @iot-rocket. - Cognito — access tokens are verified under
AUTH=true—GetUserand the other calls that take anAccessTokenaccepted any JWT carrying a user'ssub, including an ID token, a token with an altered payload and a token revoked byGlobalSignOut,AdminUserGlobalSignOutorRevokeToken; withAUTH=truethey now answerNotAuthorizedExceptionwithInvalid Access Token,Could not verify signature for Access TokenorAccess Token has been revoked, as AWS does. Contributed by @iot-rocket. - IAM — user and role tag keys are case-insensitive —
TagUserandTagRolewithdepartmentadded a second tag besideDepartment, andUntagUserandUntagRolemissed a key spelled differently; user and role tag keys now compare without case and keep the spelling last written, andCreateUser,CreateRole,TagUserandTagRolerefuse keys that repeat without case withInvalidInputDuplicate tag keys found. Please note that Tag keys are case insensitive., as does anAWS::IAM::UserorAWS::IAM::Rolewhose stack tag differs from one of its own tags only in case. Other IAM resources keep case-sensitive keys. Contributed by @gakuto-cw21. - Signer — signing material checks in
PutSigningProfile—PutSigningProfileaccepted any certificate ARN, or nosigningMaterialat all, on every platform; the Lambda and Notation platforms now refuse anysigningMaterial(InvalidProfileParameters), and withAUTH=truethe IoT and FreeRTOS platforms refuse a profile withoutsigningMaterialand a certificate ARN that is malformed, in another region or account, unknown to ACM or not issued, with AWS's errors. Contributed by @iot-rocket. - Step Functions — JSONata Fail and Wait fields are evaluated — a JSONata Fail state raised its
ErrorandCauseexpressions as literal text, a JSONata Wait failed on aSecondsexpression, ignored aTimestampexpression and dropped itsOutputandAssign, and JSONPathErrorPath/CausePathwere ignored; they are now evaluated, with AWS'sStates.QueryEvaluationErrororStates.Runtimefor a result of the wrong type, aSecondsthat is not a non-negative integer and an unparsableTimestamp. Contributed by @lucasmfraser. - S3 — presigned URLs keep AWS's time limits under
AUTH=true— anX-Amz-Expiresover 604800 seconds or not a number, or a malformedX-Amz-Date, answers 400AuthorizationQueryParametersError, and a URL dated more than 15 minutes ahead answers 403AccessDeniedRequest is not yet valid, where they were served. Contributed by @iot-rocket. - Auth — credential failures in the service's protocol — under
AUTH=truean unknown, inactive or expired access key answeredUnrecognizedClientException403 from every service; it now gets the code, status andContent-TypeAWS sends for the service's protocol, for exampleInvalidClientTokenId403 from IAM and SQS,UnrecognizedClientException400 from DynamoDB,InvalidAccessKeyId403 from S3 andAuthFailure401 from EC2. Contributed by @iot-rocket. - Step Functions —
ListExecutionsorder and pagination — executions came back oldest first, somaxResults=1returned the oldest, andnextTokenwas an offset; they now come back most recent first (running executions bystartDate, the rest bystopDate), the token resumes after the last execution returned so one started between pages is not repeated, an unreadable token answersInvalidTokenandmaxResults=0uses the default, as on AWS. Contributed by @lucasmfraser. - Cognito — confirmation codes are checked under
AUTH=true—ConfirmSignUpandConfirmForgotPasswordaccepted any code, andConfirmForgotPasswordchanged the password even when no reset was requested; withAUTH=truethey take only the issued code (123456for sign-up and654321for a password reset, as before), answer a wrong one withCodeMismatchExceptionand a code that was never issued withExpiredCodeException, andConfirmSignUprefuses a user who is notUNCONFIRMEDwithNotAuthorizedException, as AWS does. Contributed by @iot-rocket. - Cognito —
ExplicitAuthFlowsis enforced for the password flows underAUTH=true— withAUTH=truea client that lists its auth flows now refusesUSER_PASSWORD_AUTH,ADMIN_USER_PASSWORD_AUTHandADMIN_NO_SRP_AUTHunless the list enables them (the legacyUSER_PASSWORD_AUTHandADMIN_NO_SRP_AUTHnames included), with theInvalidParameterExceptionAWS returns. Contributed by @iot-rocket. - Cognito —
CUSTOM_AUTHon clients withoutALLOW_flows — a client created withoutExplicitAuthFlows, or with only the legacy names, refusedCUSTOM_AUTH; it is now enabled, as on AWS, and a client whoseALLOW_list leaves it out answersCUSTOM_AUTH is not enabled for the client.as AWS does. Contributed by @iot-rocket. - CloudFormation — API Gateway v2 stage
Ref—Refreturned<apiId>/<stageName>, causing anAWS::ApiGatewayV2::ApiMappingusing the reference as itsStageto fail withInvalid stage identifier specified; new stages now return the stage name. Stage updates, replacement onApiIdorStageNamechanges, and deletion use the resolved resource properties, including for stacks with legacy physical IDs. Contributed by @matuscongrady. - IoT — republish inside the rule's own topic filter —
CreateTopicRuleandReplaceTopicRuleaccepted arepublishaction whose topic the rule'sFROMfilter matches, so the rule fed on its own output; they now refuse it with AWS'sInvalidRequestException, and anAWS::IoT::TopicRulewith such an action fails its stack. Contributed by @iot-rocket. - IoT — deleting things, certificates, policies and thing types still in use —
DeleteThingdetached a thing's certificates and deleted it, andDeleteCertificaterefused only anACTIVEcertificate. NowDeleteThingrefuses a thing with a certificate attached,DeleteCertificaterefuses a certificate with things attached and, withoutforceDelete, one with policies attached (forceDeletedetaches them),DeletePolicyrefuses a policy with non-default versions andDeleteThingTypeone that things still use, all with AWS's messages. Contributed by @iot-rocket. - IoT —
RegisterCertificateunder an inactive CA — a certificate issued by a CA that is notACTIVEregistered anyway; it is now refused withCertificateStateException, with or withoutcaCertificatePem. An unregistered CA and a CA that did not issue the certificate are refused with AWS's codes and messages. Contributed by @iot-rocket. - IoT — rule SQL
principal()andtraceid()— both resolved to Undefined;principal()now returns the client certificate id for mTLS, the caller'sGetCallerIdentityUserIdfor HTTP Publish and SigV4 WebSocket sessions (also their lifecycle events'principalIdentifier) and the rule role's session for a republish, andtraceid()returns a per-message id that the errorAction document carries ascloudwatchTraceId. Contributed by @iot-rocket. - CloudFormation —
AWS::Logs::LogGroupdelete — a stack delete or aLogGroupNamereplacement removed only the group record, so a metric filter or resource policy added through the Logs API stayed and came back with a new group of the same name; the group is now deleted throughDeleteLogGroup. Contributed by @iot-rocket. - Cognito Identity —
GetOpenIdTokenclaims — the token was a user-pool ID token with an empty audience; it is now issued byhttps://cognito-identity.amazonaws.comwith the identity pool id asaud, the identity id assub, anamrlist naming the login providers and the user-pool sign-in, the pool ARN inhttps://cognito-identity.amazonaws.com/identity-pool-arnand a 10-minute lifetime. An identity id that no pool knows getsResourceNotFoundExceptioninstead of a token. Contributed by @iot-rocket. - CloudTrail — new trails start with logging off —
CreateTrailleft a new trail logging, andGetTrailStatusreported aStartLoggingTimean hour back and aLatestDeliveryTimeof now. A new trail now reportsIsLoggingfalse untilStartLogging, andGetTrailStatusreturns only theStartLoggingTimeandStopLoggingTimeof calls made (a restart keeps the last stop time), withoutLatestDeliveryTimeor empty error strings. Contributed by @iot-rocket. - CloudFormation — EventBridge rules accept a bus ARN —
AWS::Events::Rulestored an ARN-valuedEventBusNameas the bus name, soPutEventssucceeded without delivering to its targets. Create, update, delete and drift detection now resolve the ARN through the existing EventBridge parser and use the bus name internally. Contributed by @matuscongrady. - Cognito — SAML
/oauth2/authorizewithMetadataFile— a SAML provider created with onlyMetadataFilewas refused withInvalidParameterException; the IdP sign-in URL now comes fromIDPSSOEndpoint, then the metadata's HTTP-RedirectSingleSignOnService, thenMetadataURL. Contributed by @kjdev.