Creating an Inclusive Django Community with Kenya Phelps
Published July 15, 2026
This video features Adarsh Divakaran at DjangoCon US 2024 in Durham, North Carolina, USA.
Pygoat is an intentionally vulnerable Python Django application that can be used to learn to secure our Django apps. In this talk, we will attack a deployed Pygoat application, identify the underlying security issues in our code, and then secure it. We will learn about common security vulnerabilities (OWASP Top 10) in Django apps and how to fix them so that we can keep our applications safe from attackers.
This talk was presented at: https://2024.djangocon.us/talks/pygoat-learn-django-security-the-hard-way/
LINKS:
Follow Adarsh Divakaran 👇
On X: https://x.com/adarshd905
Website: https://blog.adarshd.dev
Follow DjangoCon US 👇
https://fosstodon.org/@djangocon
https://x.com/djangocon
Follow DEFNA 👇
https://www.defna.org/
Video production by Confreaks
Follow Confreaks 👇
https://confreaks.com
https://x.com/confreaks
Adarsh Divakaran uses Pygoat, an intentionally vulnerable Django application, to demonstrate how common web security flaws can be exploited and prevented. He shows SQL injection bypassing a login, shell injection executing commands, security misconfiguration exposing secrets, an outdated PyYAML dependency enabling code execution, and weak OTP protection allowing brute force. The practical mitigations include parameterized queries and Django’s ORM, input validation, avoiding unsafe command execution, disabling Django debug mode in production, monitoring dependencies, enforcing rate limits, and using multi-factor authentication.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Hey everyone, good evening. I'm Adarsh. I'm the co-founder and read consultant at DGO Labs. At DigiVo Labs, we provide Python and software development consultancy to our global clients to turn their ideas to reality using technology. So today we'll be attacking Pygoat An intentionally vulnerable web application written in Django, and we will learn Django security the hard way So let's start by looking at what web application security is. So it consists of a set of measures or approaches which are aimed at safeguarding servers, applications, APIs, etc. Now, let's uh take a look at some of the stats. An average website experiences uh like 172 attacks every day, and the volume of attacks against applications are doubling year over year
So, for businesses, these attacks lead to loss of credibility, they can lead to financial losses, and this can lead to compromise of user data. And for us users, It can lead to the compromise of our personal information and something like our order history, our addresses, and in some worst cases, it can lead to like password breaches or breach of credit card information. So this is a site haveibinpound. com. This was created by a security researcher where we can input our email ID and check if our data was involved in any breaches. So this is the result for my personal email ID. My data was breached in four data breaches and I think currently there are multiple uh vulnerabilities being updated every day
and If you are checking, I'm sure if you have been using the internet for the long time, at least your data will be compromised in some of these bridges. So that's the current scenario For uh due to this, we should ensure that our applications are secure. For building web applications, like uh there are a lot of resources available. We have uh lots of tutorials learning paths but uh there is relatively very less guidance and resources for building secure applications and uh due to this security is often uh learned the hard way For this, we have OWASP. OWASP stands for Open Worldwide Application Security Project.
So they are an online community. They produce freely available articles, documentation, tools, and resources. So that we can test as well as fortify our web applications. Then OWASP regularly publishes a list of vulnerabilities, top 10 vulnerabilities, which are the most commonly seen in web applications. So the current version is uh the 2021 version of a WASP top 10. These are the uh top 10 vulnerabilities Now uh coming to Python and Django, we have PyCode. PyGote is an intentionally vulnerable uh Python Django app. Which can help us learn about security. And PyGode contains multiple labs
which are like intentionally insecure applications so that we can exploit and learn about these OASP top-10 vulnerabilities. So uh in this talk we'll be going over a few of these with a demo. So let's uh start with Uh the third one in the top 10, it's injection. So injection happens when an attacker sneaks in untrusted data. So uh they it will allow them to run unindicated commands or it allow them to access unauthorized data. Some examples include SQL injection and command injection. So we have our lab one. In this lab one, our mission is to get unauthorized access as an admin.
So this is uh the setup instructions. It's like uh just another Django application. We can uh install the requirements, then perform migrations and run our Uh server for running the PyGode. So for the injection, uh we have our first slab Hi uh I am running my uh PyGot application here. Now uh let's take a look at the first slab which is SQL injection. So our mission is to log in as an admin. So let's uh try the username is admin and we can try to enter any uh random
password. So we are getting the error that the password doesn't match. Now let's go back and take a look into the code. So this is the source code. Of the query. So the application gets username and password from the request, and it just executes, it builds an SQL query, and then it just executes the query. So, this is the SQL query. And if the executed query consists of a result, we will log in that user. Otherwise, we will return a result. Let's uh see what is the vulnerability here.
This is the uh SQL query we have seen. Suppose uh the username is John and the password is password. We are using string concatenation to add name and password to this uh row SQL query. So this will be the generated query if we uh enter these values as the username and password. Now let's move to the vulnerable section. What if we enter the password as uh this string? This is a specially crafted SQL injection string. This is one of the uh basic SQL injection string, we have like multiple combinations and type of SQL injection. So let's try this basic one. So we can see the password will be replaced with this specific string And this will be the generated SQL query.
So we can see an hour condition is being injected here uh due to this string we have ended in the password field. So uh this or condition checks for uh one equal to one. So that's always true. So our password check will be skipped in this section and the user John will be logged in if you are entering the username as John. Now let's uh try that here This is the password I am uh going to paste here.
So uh yeah we cracked the lab. We could uh log in as admin. So this is the uh first vulnerability. This was the vulnerable code here. The row SQL statement was constructed based on the user provided input Next, uh, we have like similar uh another similar range of vulnerability. Uh this is for shell injection. Let's uh go through that a bit fast This is uh our lab to consists of an application for name server DNS lookups. Let's see its code. This is the code uh
of the application. So it uh gets a domain name from the uh input from the post request and it Executes either NS lookup command or d command using the domain provided by the user in the input. And it just returns the output to the user. So uh the command which was given by the user is executed using subprocess. popen. So it executes a shell command in the server system Let's see uh what happens in the lab
So first I am uh giving a domain name and I am adding one more comment uh together with that. So I have added uh the dir command. Uh this is to perform a directly listing. So we can see I am getting uh the output of the command And my working directory of the server is listed here. Similarly, I can inject any other command, like maybe I can uh run some arbitrary code or I can uh dump the NV variables on the server using this injection. So uh to prevent these kind of errors, uh one thing is uh uh we should use a safe APA, like in case of SQL, we can use parameterized queries.
Then we should also do a server-side validation of the user provided inputs and we should escape the special characters provided by the users. Coming to the Django specific mitigation steps, if you are using Django ORM, the Django ORM operations prevent uh SQLI vulnerability. So we should avoid using raw queries When possible and uh use Django RM. Next, uh, we have one more vulnerability in the injection section, which is XSS. And when we are using Django templates It has built-in protection against most of these excess attacks. And regarding other command or code execution vulnerabilities, we should not directly take input from the user and execute Uh
OSTORT system subprocess or eval like commands from these user supplied inputs. Next Next uh in the vast prop 10 is uh A5 security misconfiguration. So uh these type of vulnerabilities occur because Our application misses some security hardening and there might be some unnecessary features which might be enabled due to the presence of some default accounts and all Let's uh move to a lab one Here, our goal is to uh get a secret key.
When I am trying to get the secret key, I'm getting an error message. Only admin localhost port 8000 can access. Your X host is not. So since this is an intentionally vulnerable application, the error is directly pointed for us. Let's look at the code. The server just checks uh if a header is present and based on that it's authenticating the user. So uh to attack these kinds of things. We can use an intercepting proxy. So this is a tool used by security researchers. There are tools
like OWASP SAP or Burpsute. You might have used the network tab in the developer tools. So similar to that, we have some tools used by security researchers. So we can modify the requests, we can perform some attacks and all. So for this specific thing I am using a tool called SAP. It's an open source application by a WASP. So uh I am currently intercepting the request sent by my uh browser and this will be intercepted by this app application So I am uh turning on the proxy in the sap.
Here the request I have just sent is intercepted by SAP and I can add the requested header here So you can see that by adding or injecting the header, we got successfully access to the secret. So this is an example using another tool. It's called BurpSuit. Here we are injecting the same header and we will get access to the secret key Now,
the case here is like an example of security through obscurity. So in our case, the application trusts row inputs from the front end. So we are just taking the value of a header which can be edited by the front end. So predictable or front-end supplied values should not be trusted for authentication. And maybe uh you can think that this is an oversimplified example. Let's uh take a look at a security misconfiguration vulnerability in the real world. It's a bug which was found by Aaron Suresh Kumar in Facebook. So this allowed any attacker to delete any Facebook page. So an attacker could intercept the request to delete his own page, and they could just change
the ID of the page to the target page ID, which accepted like any public Facebook page and we could have uh deleted any pages from the Facebook. So uh in that case User 's permission to manage the page was not checked in the back end by Facebook and this was uh passed by them promptly. Next, uh our mission in this lab is to get a secret env variable. So uh this one is due to a misconfiguration, like we have or uh we have our application deployed to the public but uh we are keeping Django debug mode as true.
So we can see the 4. 4 page here lists every possible endpoint. Now we can see there is a 500 error page. I am going to that page. This is an error page generated by Django. So here all our application ENV variables, settings variables are listed here. And we can see A sensitive data is being exposed here. So this is the this is the goal of this lab. Whenever our Django debug mode is enabled, uh whether if an attacker was able to like trigger a 500 error, maybe they can try with
Some other request parameters, or they can try various things to generate a 500 error, and then our settings store PY data will be dumped and they will get access to some sensitive data So to mitigate this, whenever we are deploying a Django application to a publicly accessible environment, we should uh we should disable the debug mode. Next, for preventing uh security misconfiguration in general, we should have a repeatable hardening process and we should remove unused features. uh we should have like processes in place to manage uh manage vulnerabilities we should uh We should always review our cloud storage like permissions.
Example, like uh there's three bucket access permissions, etc. Next is A6, vulnerable and outdated components. So the previous things, like they're concerned about the code we write. But if you are using any other vulnerable or outdated dependencies, this can also lead to some security bugs in our code. So in this lab our mission is to execute uh arbitrary code on the server Let's see the lab So this lab is a simple YAML to JSON converter.
It will allow us to upload a YAML file and it will convert that to JSON and give the output. Let's uh take a look at the code. There is uh nothing much here. We are just uh using the YAML load load from the Py YAML library. We are using The library PyAML as our dependency, but uh the version we are using has a vulnerability. We are using an outdated version which has Code injection vulnerability. Let's uh see what happens. We have two YAML files. This is a uh this one is a safe YAML file
So here we can see uh the YAML is converted to JSON and we have got the output. Then Let's take a look at the evil file. So this is specially crafted YAML and this will execute this Python statement on our server. Let's try that. Here the output is none, but uh let's check our Django output. Django terminal output. You can see the statement is printed here. So we can we can add any command here, like we can use OS stored system to run system commands We can uh get the NV variables. We can run any code in the server using this exploit.
So in our case, uh the issue has cost due to an outdated or vulnerable version of PyAML. So we should uh remove unused dependencies. Then we should continuously monitor all the dependencies used and their related vulnerability information. And we should always verify If these are obtained from secure links from official sources. Next we have identification and authentication failures. So these occur when we have like some mistake. In the way we do password validation or user logins and all. Next, uh in this lab, our objective is to log in as the admin
So uh this is uh code Our mission is to log in as admin. Let's try something. Uh let's also try uh maybe the SQL injection string, but that will also uh not work here. But we have another option called login with OTP. We can uh we can add our Email address here and it will send an OTP and we can try to log in using that OTP So it's displaying a message that our
three-digit verification code is sent to our mail ID. So the one option is the real admin would have received an email with the OTP, but The OTP just have like three digits and the combination can be from 100 to 999. So there is only a possibility of total of 900 possible OTPs So we can try sending 900 requests and check if we would get access. So this is the code. Initially, an OTP is sent Next , from the post request received, it will check the ODP and email and it just scans the database. There are no CAPTCHA or like rate limits enforced.
So we can uh try to brute force the same. So I'm using uh the same tool. I'm using SAP to intercept the request. I'm starting with 100 as the OTP. So you can see our OTP request here This is the request for the OTP I have sent. Here the body contains the OTP value as 100. Next, we'll be using a tool provided by SAP to do that. Let's attack that and uh use the tool called fuzzer. Inside the fuzzer, I can specify that I need to try out this OTP with
numbers. Starting with hundred up to nine hundred and ninety-nine. So uh sap will Automate the entire process of using and it will try out the same endpoint with all these generated inputs from 100 to 999. So let's uh try out that. So it's being executed? Okay, uh to identify whether uh we have Logged in correctly, let's uh sort this by size of the response body. So uh all the remaining requests have uh this. size and one have a slightly different size. This is when uh the payload or the OTP was six
fifty three. Let's inspect that. So this is the request. We have sent the OTPS 653. Let's uh take a look at the response in that case. You can see that the login is successful in this case. The attacker could log in as admin as spygout. com. So uh we exploit a lack of rate limiting feature in this
RTP verification flow. To mitigate these kind of vulnerabilities, we should uh when possible implement multi-factor authentication. We should avoid uh default credentials and We should uh try to delay the failed login attempts. Next, uh before uh ending this, let's uh see a real-world example of this. So, this was uh this vulnerability also happened with Facebook. So, Facebook uh had a vulnerability that could let an attacker take over any other user's account. So they had a six-digit password recovery code The rate limiting was enforced on Facebook. com. The domain facebook. com. So after like 10 or 20 attempts, the user will be blocked from further attempts
But the rate limit was not enforced on beta. facebook. com domain. So using this domain, an attacker could like try all the possible combinations to brute force and get access to a user account. So these are the references I have used for this talk. You can use the Pygode project, or this is a fork where I have added these. Documentation README files, and I have fixed a few dependency issues. Next, if you are new to web security and if you're looking for some learning resources, these are some of the resources you can refer. Next, for the remaining vulnerabilities, I have added bonus slides at the end of this, so you can uh go through that.
That's it. Thanks everyone. You can Get the talk materials and you can connect with me at the following link, linkage q. co slash ardash. Thank you.
Pygoat is an intentionally vulnerable Django application containing labs that let developers exploit common OWASP Top 10 vulnerabilities and learn how to fix them.
Discussed at 2:35When user input is concatenated into a raw SQL query, an attacker can inject an always-true condition and log in without the correct password. The talk recommends parameterized queries and using Django’s ORM instead of raw SQL where possible.
Discussed at 5:58If a user-supplied domain or other value is inserted into a shell command and executed with a process API, the attacker can append commands such as directory listings or code execution. Validate input on the server, escape special characters, and avoid executing user input as commands.
Discussed at 8:17Trusting a front-end-controlled header for authentication can expose protected data, while leaving Django debug mode enabled in production can reveal settings and environment variables when an error occurs. The speaker recommends not trusting predictable client-supplied values and disabling debug mode on public deployments.
Discussed at 11:28The vulnerable PyYAML version used by the demo evaluates specially crafted YAML, allowing an uploaded file to execute Python code on the server. Dependencies should be kept current, monitored for vulnerabilities, and obtained from trusted sources.
Discussed at 16:51A three-digit OTP with no CAPTCHA or rate limit can be brute-forced by trying all 900 values; the demo finds the valid code and logs in as the administrator. Mitigations include multi-factor authentication, delaying failed attempts, and enforcing rate limits consistently across all relevant domains and endpoints.
Discussed at 21:00Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 15, 2026
Published July 14, 2026