Skip to navigation

Threat reportCloud SecurityTL-2026-2601

Unauthenticated AWS API Gateway + Over-Permissioned Lambda: Credential Extraction Attack Chain

highACTIVE

GuidePoint Security's Threat and Attack Simulation (TAS) team demonstrated a repeatable AWS serverless attack chain: an API Gateway method left at the default authorizationType NONE fronts a Lambda function that passes unsanitized user input into Python's eval(), letting an attacker with no AWS credentials enumerate the API, pull the Lambda's source, inject a payload to read process environment variables, and exfiltrate the function's temporary IAM execution-role credentials (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_SESSION_TOKEN) via the HTTP response.

Key facts

IdentifiersTL-2026-2601
SeverityHIGH
First disclosed
Affected productsAmazon Web Services Amazon API Gateway (REST API v1 and HTTP API v2) methods backed by AWS Lambda
Weaknesses (CWE)CWE-95, CWE-250, CWE-276
MalwarePython
ToolsAWS CLI, curl
MITRE ATT&CK techniquesT1059.006 Python, T1059.009 Cloud API, T1078.004 Cloud Accounts, T1087.004 Cloud Account, T1190 Exploit Public-Facing Application, T1526 Cloud Service Discovery, T1528 Steal Application Access Token, T1552 Unsecured Credentials, T1580 Cloud Infrastructure Discovery, T1595.002 Vulnerability Scanning
MotivationUNKNOWN
Detection rules9 (1 shown free)
Sources9 cited sources

Detection coverage

As of 2026-09-21, Threadlinqs Intelligence publishes 9 detection rule(s) for TL-2026-2601 across Splunk SPL, Microsoft KQL and Sigma, covering 11 indicator(s) of compromise. The whole corpus is readable without an account. Every threat comes with one complete detection in Splunk SPL, Microsoft KQL and Sigma, free for everyone; a free account adds daily TL Creds to unlock the rest. Paid plans add a larger daily allowance, correlation and the MCP server. Threadlinqs MCP server · View plans.

Free detection: Unauthenticated API Gateway eval() Injection Payload (Exploitation)

Detects HTTP requests reaching an API Gateway method left at authorizationType NONE where the decoded query string contains Python eval/exec-injection markers (__import__, os.environ, os.system, subprocess., eval(, exec() ) β€” the exact CWE-95 sink abused to read the Lambda execution role's environment variables through `result = eval(user_input)` in vuln-lab-get-user-data.

  • Languages: Splunk SPL, Microsoft KQL, Sigma
  • ATT&CK: T1190, T1059.006, T1595.002
  • Data sources: aws_apigateway_access_logs, aws_cloudtrail
  • Severity: critical
  • Confidence: high

Splunk SPL

index=aws_apigateway sourcetype="aws:apigateway:accesslogs"
| eval decoded_query=urldecode(queryString)
| regex decoded_query="(?i)(__import__|os\.environ|os\.system|subprocess\.(popen|call|run)|eval\(|exec\()"
| lookup api_gateway_auth_config.csv resourcePath OUTPUT authorizationType
| where authorizationType="NONE" OR isnull(authorizationType)
| stats count min(_time) as first_seen max(_time) as last_seen values(decoded_query) as payloads by sourceIp, resourcePath, httpMethod
| where count > 0
| sort - last_seen

Microsoft KQL

AWSAPIGatewayAccessLogs_CL
| where TimeGenerated > ago(24h)
| extend DecodedQuery = url_decode(RequestQueryString_s)
| where DecodedQuery matches regex @"(?i)(__import__|os\.environ|os\.system|subprocess\.(popen|call|run)|eval\(|exec\()"
| where AuthorizationType_s == "NONE" or isempty(AuthorizationType_s)
| summarize Count=count(), FirstSeen=min(TimeGenerated), LastSeen=max(TimeGenerated), Payloads=make_set(DecodedQuery) by SourceIp_s, ResourcePath_s, HttpMethod_s
| order by LastSeen desc

Sigma

title: AWS API Gateway Unauthenticated eval() Injection Payload
id: 7f2a1e3c-4b5d-4a6e-9c7f-1a2b3c4d5e6f
status: experimental
description: Detects Python eval/exec-injection markers in API Gateway access-log query strings on methods left at authorizationType NONE, consistent with the GuidePoint TAS serverless credential-theft chain (result = eval(user_input)).
references:
    - https://www.guidepointsecurity.com/blog/serverless-not-riskless-exploiting-unauthenticated-api-gateways-in-aws/
    - https://cwe.mitre.org/data/definitions/95.html
author: Threadlinqs Team
date: 2026-09-21
tags:
    - attack.initial-access
    - attack.t1190
    - attack.execution
    - attack.t1059.006
    - attack.reconnaissance
    - attack.t1595.002
    - cwe.95
logsource:
    category: webserver
    product: aws
    service: apigateway
detection:
    selection_payload:
        cs-uri-query|contains:
            - '__import__'
            - 'os.environ'
            - 'os.system'
            - 'subprocess.'
            - 'eval('
            - 'exec('
    selection_noauth:
        authorization_type: 'NONE'
    condition: selection_payload and selection_noauth
falsepositives:
    - Authorized penetration testing / red team exercises
    - Sanctioned DAST scanners fuzzing injection payloads
level: critical

Known false positives:

  • Authorized penetration test / red-team exercise against the same endpoint
  • Automated vulnerability scanner (e.g. Burp, Nuclei) fuzzing eval-injection payloads as part of sanctioned DAST

Tuning notes: Scope the index/table to the specific API Gateway REST API ID(s) fronting Lambda handlers known to call eval()/exec(); widen the regex to cover base64-encoded or URL-double-encoded payload variants attackers may use to evade this exact string match.

8 more detection rules (Splunk SPL, Microsoft KQL, Sigma) · unlock with TL Creds. Sign up free to unlock the detection rules or query them with the Threadlinqs MCP server (Purple)
  • AWS API Gateway / CloudTrail Reconnaissance Burst (Enumeration) · unlock with TL Creds
  • Sequential Multi-Variable Credential-Harvest Pattern Against a Single API Gateway Resource (Post-Exploitation) · unlock with TL Creds
  • GuardDuty ResourceCredentialExfiltration.OutsideAWS Correlated with Secrets Manager Access · unlock with TL Creds
  • Lambda Deployment Package Source Retrieval via Pre-Signed Code.Location URL · unlock with TL Creds
  • AWS Credential Environment-Variable Names Referenced in Unauthenticated HTTP Request · unlock with TL Creds
  • Lambda Execution-Role Session Performs Privilege-Escalation-Capable Calls via Non-Lambda User-Agent · unlock with TL Creds
  • Lambda Execution-Role Environment-Variable Credential Harvest via eval() Sink (Post-Exploitation) · unlock with TL Creds
  • Stolen Lambda Execution-Role Credentials Used from Outside AWS for STS/Secrets Access (Credential Reuse) · unlock with TL Creds

Indicators of compromise

As of 2026-09-21, Threadlinqs Intelligence tracks 11 indicators of compromise for TL-2026-2601.

Sample indicators (1 of 11)

  • URL: hxxps://7793fgpqri[.]execute-api[.]us-east-1[.]amazonaws[.]com/prod/vulnerable/get-data

Defanged, TLP:CLEAR. Full set of 11 indicators: unlock with TL Creds.

11 indicators of compromise · unlock with TL Creds. Compare plans

Technical analysis

Because the demo execution role was over-permissioned with secretsmanager:GetSecretValue, the stolen credentials were then used to pull database secrets from AWS Secrets Manager.

GuidePoint Security's TAS team built an intentionally vulnerable AWS lab (API Gateway REST API 7793fgpqri, region us-east-1, stage prod, fronting three Lambda functions) to walk through, end to end, how a single unauthenticated HTTP request to a misconfigured serverless stack escalates into IAM credential theft and secrets exposure. Amazon API Gateway leaves a method unauthenticated (authorizationType: NONE) unless an authorizer -- AWS_IAM, a Lambda authorizer, or an Amazon Cognito user pool -- is explicitly attached to it; because that authorization has to be configured per method rather than enforced by an account-wide policy, it is easy for a method to ship without it. Enumerating the lab API's resources and methods (aws apigateway get-method, checking authorizationType/apiKeyRequired per resource) found all three backing Lambda functions -- vuln-lab-get-user-data, vuln-lab-process-report, and vuln-lab-search-records -- exposed at the default NONE with no API key required. Deep analysis focused on vuln-lab-get-user-data, whose deployment package (retrieved via the pre-signed S3 URL returned by aws lambda get-function's Code.Location field) showed request input passed straight into Python's eval() (result = eval(user_input)), a textbook CWE-95 eval-injection sink.

The walkthrough runs in ten stages: (1) enumerate the account's deployed REST APIs (aws apigateway get-rest-apis), (2) enumerate each API's stages (aws apigateway get-stages), (3) enumerate resources and check each method's authorizationType (aws apigateway get-resources / get-method) to find all three endpoints left at NONE, (4) retrieve the vulnerable Lambda's deployment package via its pre-signed Code.Location URL to read its source, (5) analyze that source for the eval() injection point, (6) craft and send three separate GET requests -- each with a --data-urlencode "user=__import__('os').environ['<VAR>']" payload -- through the unauthenticated endpoint into the eval() call, one per targeted environment variable, (7) recover the temporary AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY/AWS_SESSION_TOKEN that Lambda auto-injects for every execution role from the three HTTP responses, (8) export the recovered values as local environment variables to adopt the stolen identity, (9) confirm the resulting identity and permissions via aws sts get-caller-identity, and (10) use those credentials to call aws secretsmanager get-secret-value (secret ID vuln-lab/database/master) and retrieve database/application secrets -- possible only because the demo execution role (vuln-lab-lambda-execution-role) had been granted secretsmanager:GetSecretValue well beyond what the function itself needed. GuidePoint further notes that if the execution role also carried iam:PassRole plus lambda:CreateFunction/UpdateFunctionConfiguration/UpdateFunctionCode, the same stolen credentials could pivot into persistence or broader privilege escalation.

No CVE applies: this is a misconfiguration- and design-pattern-driven technique, not a single-product vulnerability, and GuidePoint states the underlying defaults and misconfigurations 'exist across production environments right now' based on their client assessments -- though the walkthrough itself was run purely against their own lab environment (the API ID, function names, and secret path above are that lab's illustrative identifiers, not live production infrastructure), with no claim of in-the-wild exploitation. The chain is entirely enabled by two independent, individually common misconfigurations (an unauthenticated method, and an over-permissioned execution role) stacking on top of unsafe dynamic code execution; removing any one of the three breaks the chain, and the discovery of three separate exposed functions behind one API underscores that the misconfiguration tends to recur across an account's endpoints rather than appear once. GuidePoint's own recommendations are to require authentication on every API Gateway endpoint that doesn't need to be public, never pass user-supplied input into eval()/exec(), and scope every Lambda execution role to least privilege.

MITRE ATT&CK techniques by tactic:

Execution

T1059.006 Python; T1059.009 Cloud API

Privilege Escalation

T1078.004 Cloud Accounts

Discovery

T1087.004 Cloud Account; T1526 Cloud Service Discovery; T1580 Cloud Infrastructure Discovery

Initial Access

T1190 Exploit Public-Facing Application

Credential Access

T1528 Steal Application Access Token; T1552 Unsecured Credentials

Reconnaissance

T1595.002 Vulnerability Scanning

Remediation

Immediate actions

  • Require authentication (AWS_IAM, a Lambda authorizer, or Amazon Cognito) on every API Gateway method; audit all deployed stages for methods left at authorizationType NONE
  • Rotate the affected Lambda execution role's credentials and review CloudTrail for any API calls made with them since the exposure window began
  • Remove or disable any Lambda function that passes user-supplied input directly into eval()/exec() until the code path is fixed

Workarounds

  • Front any endpoint that cannot immediately get IAM/Cognito auth with AWS WAF and a resource policy restricting source IPs or VPC endpoints

Longer-term hardening

  • Scope every Lambda execution role to least privilege -- remove secretsmanager:GetSecretValue, iam:PassRole, and other broad grants the function does not genuinely need
  • Stop storing database/API credentials in Lambda environment variables in the clear; fetch them from AWS Secrets Manager or Parameter Store at runtime under a narrowly scoped IAM policy
  • Enable Amazon GuardDuty (including the ResourceCredentialExfiltration and CredentialAccess finding families), CloudTrail data events, and API Gateway execution/access logging on every account
  • Add pre-deployment static analysis / code review gates that flag user input flowing into eval(), exec(), or equivalent dynamic-execution sinks

Affected and fixed versions

  • Amazon Web Services β€” Amazon API Gateway (REST API v1 and HTTP API v2) methods backed by AWS Lambda
    Vulnerable versions: Any API Gateway method left at the default authorizationType NONE, backed by a Lambda function that passes user input into eval()/exec() and whose execution role is over-permissioned
    Fixed in: N/A -- this is a configuration/design hardening issue, not a versioned software vulnerability

Timeline

  • Because the execution role was over-permissioned with secretsmanager:GetSecretValue, the stolen credentials are used to retrieve database and application secrets from AWS Secrets Manager.
  • The stolen credentials are used to call AWS STS get-caller-identity and confirm the identity and permissions granted by the compromised Lambda execution role.
  • The three captured credential values are exported as local environment variables, adopting the identity of the compromised vuln-lab-lambda-execution-role for subsequent AWS CLI calls.
  • The Lambda execution role's temporary IAM credentials (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN) are returned across the three HTTP responses and captured.
  • Three separate curl GET requests, each carrying a --data-urlencode "user=__import__('os').environ['<VAR>']" payload for AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN respectively, are sent through the unauthenticated API Gateway endpoint into the vulnerable eval() call to read the Lambda process's environment variables one at a time.
  • The vuln-lab-get-user-data Lambda's deployment package is retrieved via the pre-signed S3 URL returned by aws lambda get-function's Code.Location field, and its source analyzed, revealing that user-supplied input is passed directly into Python's eval() (result = eval(user_input)).
  • Resources and methods on the discovered API are mapped with aws apigateway get-resources/get-method, and each method's authorizationType is checked, revealing all three backing Lambda functions (vuln-lab-get-user-data, vuln-lab-process-report, vuln-lab-search-records) left at the default NONE with no API key required.
  • Walkthrough begins by enumerating deployed REST APIs and their stages in the target account/region to identify reachable API Gateway endpoints.
  • GuidePoint Security's Threat and Attack Simulation (TAS) team publishes 'Serverless, Not Riskless: Exploiting Unauthenticated API Gateways in AWS', documenting a full unauthenticated-to-credential-theft attack chain against a lab AWS serverless environment.

Sources cited

Previous and next in cloud

Drafted by the Threadlinqs research pipeline from 9 sources; published ; last updated —.

Threadlinqs Intelligence β€” Real-Time Threat Detection Platform

// threat_feed
$ sort --newest
Showing all threats

Live intelligence console

Threat level

Latest Threats