You shall not pass! 🧙 Strengthen your python code against attacks.

,

This talk will highlight the theoretical concepts on security. We’ll start with a general overview and dive into specifics for Python applications. We will address five main questions:

  1. How can we retrieve a password with a Python function?
  2. What are the most essential IT Security practices?
  3. Where can we find information on current security vulnerabilities?
  4. What should we keep in mind to write secure Python code?
  5. What are some historical attacks on Python code? What can we learn from them?

Listeners will walk away with a general overview of how to approach security issues when building their Python application and make their future code more secure.

This session took place in track Security and was classified suitable for novice domain / intermediate python by the speaker.

Transcript (auto)

Auto-generated from the recording utilizing Open-Source AI. Speaker labels (Speaker 1, Speaker 2) reflect diarization, not identity. Timestamps refer to the recording.

Speaker 1 [00:06]

Thank you very much for that warm introduction, and also from us, a very warm welcome to every one of you here and also online. We're going to be looking at strengthening your Python code against attacks. And the first thing that I want to say is we know that it's really hard whenever you get into security to... Sorry, I missed it. I had a blackout. Okay. Maybe we're going to start with the introduction until I figure out what to do. Roman, you want to start introducing yourself?

Speaker 2 [00:47]

As you already know, my name is Roman Kraft, I'm a software developer at PD, which is a

Speaker 1 [00:48]

Yeah.

Speaker 2 [01:02]

public sector consulting company in Germany, and an important thing for this talk is that we are not security experts, we just got very interested in this whole topic because of some current developments that we followed in the news and wanted to just share our knowledge with the whole community. So if you are a security expert deeper in this whole section, there's a good possibility that we are not going to tell you anything really new, but it's rather going to be a little bit of the basics and how every one of us can work on making the coding environment for everyone just a little bit safer.

Speaker 1 [01:43]

I'm very happy Roman remembered the words better than me. So yes, I'm working at the same company as Roman, and the issue that actually got us here today was that we stumbled across a vulnerability and a package that we were using, which is called Gradio, where we can use the package for showcasing your ML model, and you can use it with a public link. And in the vulnerability, you can actually exploit this and get access to arbitrary files on your PC, and we thought, like, this can't be true. No way this is going to work. But then when it actually worked, we got very shocked, and then we also got intrigued, thinking of all the things that also might we might be missing. So, yeah, this is going to talk is going to show a bit about this. But first things first, we're going to start off with the basics to get everyone on the same page. So we all know this. We have seen it 100 times. We update our software. We use secure passwords to factor authentication. Most of the times we're actually forced to do so, but, yeah, we're well aware that it makes our account secure. We also use antivirus software and we don't think about firewalls anymore because, yeah, they're in place all the time. We're also maybe careful when we look through our emails, we won't open any phishing emails because we don't want to install malware. And then, when we code, we go ahead and type pip install matplotlib into our terminal, and then, oops, this happens. We might have encountered a typosquatting attack, meaning, for those who don't know, a typosquatting attack is when malicious actors upload some package on Pypi where pip install takes the package from, and gives it a name that is spelled very similar to the original package. You saw it in the case of the Matplotlib, it was only changing the M and the A, and when we download this PIP package, we then install malware on our PC, or we just install a malicious package, and from there, any code can maybe be executed, or we give access to system to some malicious actors. So this example also shows us, unfortunately, that often the easiest way into a system are our own behaviours. So when we work very fast, or we don't think about something, and maybe do some habits that we all have, these are very easy to exploit, And this is also what malicious actors actually look for and try to use. The next basic we're going to touch upon is the basic of information security, which concerns our personal information. We have three pillars which are looking at availability, which means that we have access to our information all the time when we need it, for example, our user accounts, the integrity that looks at that the data that we are given is not, ensures that it's not tampered with or someone else have changed it. And also the third one is confidentiality, which tries to ensure that only we have access or only authorised people have access to the information that we use. And this is certainly not sharing our secrets openly on GitHub. So last year, 12 million secrets were shared on GitHub. And I might have been one of them, I don't know. But from now on, I hope we won't be any of those. And yeah. So we can see that we have to be cautious while developing. And this might, like, it might be hard, but there are techniques we can apply. We can even do pair programming. But even if we are very careful, and we think about every step, and try to write everything correctly, there's still things that we don't know about and that, like, always pose a threat to the code we produce. So, we're going to go through an example together, actually doing mob programming in a large scale, and we're going to start a small sample application that is just going to implement some password check. So, we're going to start very slow, mining everything, where we have a user that's going to input a password, then we're going to take the input from the user and check it against the real password, which we maybe took from a database, then here we have this check password function. This is the part we're going to look at, and then we're going to issue true or give access to the app if the password is correct, or ask to re-enter if not. So here's the small implementation. We have the check password function. If we run this, we can see we can enter a really easy password, and it gives us access. Okay. So let's look deeper into this check password function that we implemented. So we have the real password, and then we define a function, and we're looking whether the length of both passwords are the same. If not, we can issue false right away. If they are the same length, we're going to go through character by character or place by place and check if the integers in this case are the same. So if there's an error, if they're not the same, we issue false, and if all the parts of the function are correct, we issue true. This is actually the same logic that is implemented behind the statement password equals equals retreat function. So, what could possibly go wrong? Well, if we try to break through the system now and play the evil hacker, maybe, then we can think of a function where we use kind of the response time of the system in order to guess what the correct characters of the password function is. So, we're going to start off by the initial number, like, for example, 0, 0, 0, and then we're going to go through each digit and measure the time that it takes for this check password function to issue true or false. And if it takes a bit, like, well, if it returns true, then we know it's the correct password, we can use it, but if it returns false, we compare this time taken to the time we know it takes the system to respond to check one character. Because if the time is a bit larger, then we know that it actually had to move to the next character in line to check it because the first one was correct. So we can move like this through the function and check for the right password. Of course, there are many more ways to break through this function, but it was supposed to showcase that there are also system level things, like this is called a side channel attack that uses system level information in order to gain access to the PC, and these things are not present in all our minds when we code. So if you compare how this attack, like, goes against brute force attack, which is just trying every number that we can come up with, we can see that it's way faster. It takes only two seconds as compared to 25, but with this easy password, it's actually the fastest way to just take some common password list on the internet and compare it, and then we're through in less than a second. Enough on the basics. It was the introduction. And to, well, yeah, conclude the introduction, here's a small data health check that you can do yourself. Most of you probably already know the have I been pawned to check your credentials and also the passwords list. Many password managers actually go through this. But there's a new thing which is called, has my secret been leaked? So in case you, especially for ML people maybe that use a lot of tokens, you can check whether your token has been leaked to. And here, a tip on, yeah, how to do your password before random words. Now Roman is going to go more deeper.

Speaker 2 [10:16]

And we're going to take over now, and we're going to talk about explicit coding risks. First off, I'm going to give a little overview about the difference between vulnerabilities, bugs and exploits, because all these three words are used very interchangeably, and you just want to get a little bit of differentiation in there to better know what we're talking about. And after this, I will talk a little bit about often occurring vulnerabilities in Python, And after this we will actually showcase you two of the vulnerabilities that we found and how to exploit them, including the one involving radio, where we're going to steal a picture from each other. So vulnerability in general is a theoretical problem in your system design. It's just some kind of case that you overlooked and that is not really applied in your code. So if your code reaches the state, it's doing something that is really unexpected for you. But if you try to differentiate it against a bug, a bug is something that is let's be a little bit mean. That's really our fault. It's a programming error. I made a mistake, somewhere along the code I'm doing something that I wasn't supposed to for this case, that is just plain wrong, and this can again be used to get the system to act in a way that was not intended and will do arbitrary things that I didn't want it to do initially. But all of these problems are theoretical in nature, they are in the code base, but at this point there is no real problem attached to them. This differs with an exploit, an exploit is the actual realisation of an attack using this problem in your code, whether it be a vulnerability or a bug. So if you know that your code has vulnerabilities, there is a possibility that there will be some kind of malicious actor that is creating the exploit targeting exactly this problem. The good news is you don't have to remember all vulnerabilities that there are, and you You don't have to search for them alone. There are databases that are publishing them regularly. One of the most well-known ones is CVE, where many people are publishing bugs or vulnerabilities that they found in the code, alongside with very basic exploits for this code problem, because you need to showcase that there's actually a way to exploit this, other than, yeah, there's theoretically an error in this giant code base. It can never be reached, but theoretically it's there because you always want to use your time most efficiently and, in this case, on real existing problems. Now common problems, common vulnerabilities in Python would be one of the most well-known ones. It is actually not really from Python, but it's SQL injections. SQL is still one of the most used database languages across all coding languages, and if you don't sanitize your inputs well, you can give the user way too much access to your database. Many of the more sophisticated SQL packages already do this for you, but it's not a good of thinking to only rely on them. Because if you don't do this the correct way, the user can just access all of the accounts, can access data that it wasn't supposed to be for his or her permission level, or even drop the whole database, as is illustrated with this XKCD comic. Another big problem for Python is the deserialisation. Whenever we store some kind of Python code for long term, or even only larger configuration files, there can be a problem when Python reads these files in, that some part of this data will be read in a different way than was intended. Or even if you get this file from some output source, that it was put there maliciously. This can then lead to many different problems. One of the worst ones that there is, and also one of the worst vulnerabilities that can be thought of, is remote code execution. It's basically when a malicious actor has complete access to your system, they have the permission or somehow found a way to actually execute code on your system, and I don't need to tell you that this is a really bad situation to find yourself in if you don't really trust this party to execute only good code. The last problem, last vulnerability that's also the one that was used in the Gradium is path traversal or dot dot slash attacks. They are mostly found in web applications where you're deploying some kind of web server. They as you all know these servers always live in some kind of directory structure where where all the files are stored, pictures, and all the text that is used on this website. But technically, they are deployed on some kind of system. And Gradius is often deployed on your own system or the one that is given to you by your company. And there's much more data on there than you actually want to show the user. And with this path traversal attack, you can kind of escape this web server directory space And access any kind of file that is on the system. And as Antonio already said, there's not a guarantee that they really will find some targeted thing. But there are many common known files where passwords are stored or some other cache is stored. They can get system information about your complete setup and then know maybe about some other vulnerability they can exploit. So, it can lead to many different other attack vectors. Now we're going to start with the examples. The first one is the path traversal using Gradio. And for this I will assign Antunia the task to actually deploy the server, because I don't want to. And I will assume the role of the malicious attacker and steal some file from her PC.

Speaker 1 [17:11]

So, shortly going through, we said it sometimes, but we wanted to, like we deployed a machine learning model to showcase it to others, and we put a small demo app together for you, so what this app is doing is just starting an interface with an image in it, so you need to have content in it to start this file route where you then can escape from what Roman was explaining, so when we run this app, we get the public URL, we're just going to click on it, and I'm going to enter, go outside of the mode, yeah, so this is the Gradu app pretty easily implemented, and here we have an image, and here we can see where the image is stored, kind of stored on our system, and then what Roman is doing on his PC right now, with a different app, because I don't want anyone to hack into my PC, is to copy this path, and then I'm going to exit this app, too, so my system stays secure, and then you kind of use this in your terminal, you can enter this command, which is just accessing this path with list only and path as is argument, and the important part is after we go kind of to where the file is stored, we then go up some directories, meaning dot dot slash goes backward in your path file, and then we enter the path to the asset we want to to steal, and then we enter the output path where we want a copy to be put. And if you now think, well, no one is going to guess where my holiday pictures are lying, well, there's many system-level paths that are known or that are the same on each system, and over these paths, these files can be accessed. And then if you apply, then, yeah, for those watching online maybe, we put together here what the output will look like, and then you would have access to this image. Did you hack into my...

Speaker 2 [19:36]

Sadly, no, because as it is tradition for live talks, my computer basically bluescreened. Okay. So... But we tried it out beforehand, it worked, I promise. Yeah.

Speaker 1 [20:02]

You can try it out yourself.

Speaker 2 [20:03]

yourself. It would be the same picture, I promise. But we uploaded this whole code on GitHub, the link will be at the end of the talk. And you can test it out yourself there. So we are going to move forward with remote code execution. Let's kind of set the scene. You found some kind of web application that you want to deploy on your own system. Just some kind of flask web server that is providing some kind of service. It doesn't really matter what it is. You found this repository, thought it looked great, looked a little bit over the code, everything looked safe, and then you clone it to your local system and run it. That's what I'm going to do. I'm going to run this random repository I found that I completely trust. And this is not supposed to happen. As you can see in this code, nowhere is actually some kind of message box created. There's not supposed to be anything popping up. But it still did. And this is at this point stopping the system. If it wouldn't do this, the rest of the application would actually start up completely normally and would be available now. Now if you try to look into the whole codebase, which is only 20 lines long, so it's easy, you can see there's nothing. Nothing is doing this. So where does it come from? Now we try to get into the configuration files because it's loading a YAML. Maybe something is in this file. The first thing that should surprise you is that it's very long. This is never a good sign if only three attributes of this whole file are used, why is it so long? And if you look a little bit closer, especially at the end, then we find it. I didn't hide it very well, so you can read the actual code that is used, and I'm starting up a new subprocess that is actually installing a new package that I'm using for this message box. And all of this was possible without any interaction on my part. So if I was really a malicious actor, I could use this vulnerability to install some kind of package that is completely malicious, or even just one of those typosquatting packages that are then using your system however they like. And what surprised me personally with this vulnerability is that the YAML loader for is a very basic package, in my opinion. It's used far and wide, and this vulnerability is not that old. It's only from 2020. And it was, in my opinion, a very good sign that there's not really some kind of level that you can apply to the dependencies that you use, where you're just thinking, oh, yeah, it's always going to be safe. I never have to look into this one. It's just YAML. It's just Flask. It's just Pandas. So many people are using it, inviolability will be guaranteed to be found. This is never the case. There can always be problems that arise, and you always need to stay vigilant. And now we talked very much about risks and problems, and now we want to talk about some ways to actually mitigate these problems. First, I will go into a little bit about different code scanners and what you can do with them and how they can help you to actually secure your code base more. Mostly code scanners are used for linting and formatting, which is a great use case. Good code hygiene is always important and will also help you in security aspects because it will stop you from uploading confusing code that you yourself won't even understand after let's say six months. At least I don't, if I look at something I wrote six months ago for myself, then only God and I knew what I was doing, then now only God knows. There are also many code beginners that actually will search for known vulnerabilities using different databases like the CVE database, but there are also many more where many people are actively searching for vulnerabilities because they want to make code safer. Some might also say because they are making money from it, but never assume bad things. It also helps you get a basic overview over your dependencies you're using, because as I said, I didn't say at this point, sorry, because Python is a very interdependent language, your packages that you are actively installing have subdependencies, and those subdependencies have sub-subdependencies, and so on and so forth, so at some point you won't even really We know what's in your environment anymore, because you just installed 10 different packages, each of them you are using 11 more, and at some point you're just wondering, why even do I have this? I won't give you a complete list about different linters that are there, especially the one for code hygiene and formatting. Most of the IDEs that are available are using them automatically, but there are also ones that are specializing in security aspects. One of them is Bandit. Bandit has very many different security vulnerabilities that are actively searching your code base and then displayed. I can give you a little example. It will even give you warnings for code packages that can have problems or that are just not advised to use. One of them would be things like the subprocess package because you should never really want to use this if there's any other way to achieve the same result because starting up a shell is always a bad idea from your code. You're just opening a box that you don't want to open. But it's also warning you against possible SQL injections when you are just creating a query with some kind of user variable. It's giving you a warning that you should sanitize it correctly And not just enter something that you found, that the user found and just entered, but it needs to be secure. It's giving you even severe warnings if you're actually using these subprocess functions or something from the OS package. We're just calling a shell script because, again, that's nothing you should do lightly. and if there's any other way you should do it that way, because it's just a huge risk. We are also having the deserialisation problems, where it's warning us, pickle is one of the most used for Python, it's again just giving us warning, you are deserialising data, maybe you should be very aware that you are only deserialising trusted data, because there problems with that. And what's also very nice for if you're not very put together in the terms of remembering things, as I also am, it's also giving you warnings when it finds some kind of variable called password with a clear text, because then you just enter the password and clear text in your code base, and if you're trying to publish it to GitHub or Pipey, everyone will have this password. Which I wouldn't like. Then there are also the dependency scanners. As I said, you are building these whole dependency environments, and if you want to check them all by hand, it will take you days, months, and no one of us has this time. So we want to automate it. And for this, there are different possibilities like safety, dependency check, or a pip audit. We will go into this a little bit more when we're talking about package management in general. So here's no example for you. But all of this is really important for your own code. There is another kind of goal you should set yourself if you're publishing your code, like if you put it to some kind of Git repository. GitHub and GitLab both have ways to automate all these things and even publish the reports. And if you are really savvy, you can also set thresholds for your own code. So it will only commit, pass this commit or accept this merge if there is some kind of security baseline given, otherwise it will just not allow you to do this. I will go over an example a little bit more thoroughly. It's a GitHub action example. As you can see, it's not very long. It's also just starting up the scanners I want to have and then publishing these reports on the repository itself for everyone to see. It will only do this if I'm involving the main branch, whether it's a push or pull request. And the things I'm going to do is just checking out the repository, then I will install Poetry to actually install my environment and set it up. And after this, I'm just running Bandit and some other scanners, like also Safety. And all these reports are stored in different files. And these reports will then just be published on the repository. But what is great about this for everyone is that if I now just see this public repository and find some kind of safety report, I can look into it and be more sure that the maintainer of this repository actually cares about safety. And security. And it's not just writing code and pushing it out on GitHub and hope that nothing breaks. So I will be more calm in using this code myself. The next part in publishing code would be to actually package my code as a package and deliver it on some kind of delivery system like Pypi or Conda. Conda has a pretty strict workflow, what they are all checking, but the most used one is still Pypi, and Pypi doesn't really check much. They just now started up some kind of two-factor authentication that you need to use to publish your code. But there are not really many safety guidelines or checks that they are doing. This is all built very much on trust between developers. And as we all want to trust into each other, we also need to set ourselves this guideline to have as secure code as possible. So, if you want to publish a code, there is no way around really setting up automated pipelines, checking your code thoroughly, checking your dependencies, checking whether you really need some kind of old package or there can be a newer version that is just as good. And this is just all something that we need to uphold ourselves, because otherwise the The only thing that could be done is to limit the access to publish new packages. And I don't think that's something we should strive for. I think every one of us should be able to publish their code and have it just as open as possible. With this, I'm now going to, we're going into a public package environment and Antonia will take over.

Speaker 1 [32:27]

They're scanners and everything. But what do I do if I don't want to install the package in the first place because I don't know what is in the package? We heard of the typospotting attack in the beginning. So starting from the point where we Google and then we get a suggestion to pip install some package in a Stack Overflow solution, well, the first thing, think of the human factor and be cautious. Check if there's maybe a GitHub repo. Check for this high risk expressions if you just want to scan it kind of through, like for subprocesses run, exec, eval functions. Check also the init.py file at the beginning or the setup.py. These are popular targets where code is ingested into. And also check for HTTP requests that might exfiltrate some data. So you can go to the GitHub repo and then use the search function. But well, I guess we're not going to be audit experts, and we all have many other things to do, so we should use tools that can actually do this for us or at least help us in the process. So if you still need some proof or want to be extra sure, like Roman also touched upon, You can check databases that give you also tips on how to fix issues that are in packages. You can also scan pipy packages before downloading using guard dock. It's actually a tool that you install, and then you check the package that you're about to install, and then it tells you whether there are vulnerabilities in there. And you can also maybe download the package manual before installing it, and then checking it with a code scanner, but, yeah, that would also take a lot of time, I guess, and maybe be not very convenient. And if you really want to try out this very, very risky package, and you can't help yourself, then maybe use a sandbox environment. There's actually one available from philium command line interface, so there you can try it out in a safe environment. Roman touched upon it, dependency management, it's a very important part, especially when you're sharing code and you want others to use your application, so there are a few steps you should make sure when you use your environment. I know environments can be a really tricky topic, and we all have our favorite environment setups and things, but there are three things you should make sure you have, which is all are included in log files, and log files contain, in the ideal case, you should aim for specific pinned versions, so you make sure that when you've checked the package and you decided it's safe to download, and you downloaded it, that you pin the version in your log file so you only use this version. Because if you, for example, use a loosely defined dependency, then every time you reinstall the environment, what's going to happen automatically is that it maybe goes on PyP and downloads another package which might have some malicious code in it. And also, the hashes are stored with this. These are like keys that are issued when something is published on PyPE. There's a whole discussion going on on how useful these are, but you can check the hashes. And yeah, you should have the full dependency tree in your log file. And also, pip audit is a good tool to scan your environment. You can use it right now and check if you have any packages in your environment that are malicious. In our case, we can see it gives us out Gradio and PyML, the versions we use, that they have issues. And, yeah, this is more an advanced tip. But if you're on a company level, you can actually make your own PyPE repo or mirror some PyPE packages into your repo. So, yeah, coming to an end, there's, of course, many, many more topics that we could have touched upon. Here's a small selection we put together for you. We hope you found it enjoyable or useful in some case. And yeah, feel free to connect. And maybe we can talk to you later. Or we're excited for your questions. So thank you very much.

Speaker 3 [37:25]

So thank you a lot for this talk. It was a wonderful talk, and we got a lot, a lot of questions. So I'm just starting. So one question is, does Parflip or any other standard library provide facilities to prevent path traversal attacks? Or I would extend this question. So when there's a standard library, do they document the best practice how to use them and how to avoid risks? What do you think?

Speaker 1 [37:53]

In the package you're using or

Speaker 3 [37:55]

Yeah, so when I want to use a package and I look at the documentations, how aware are they about security risks? So is this an issue? Absolutely.

Speaker 1 [38:06]

When I read the documentation, I haven't come across many evaluations of their own packages. So I would think there could be done much more. But I also think that we can actually, with our own practices, just do the due diligence a bit ourselves when we have these scanners installed and they're running automatically, then we might be hinted to some of these issues. Yeah, especially in the open source community where there's so many contributions, which is really great. Of course, not everyone is checking out the standards or suggestions there are for secure implementations. But there are some on PyPE, for example. Sorry.

Speaker 2 [38:49]

I just want to add that this is highly dependent on the package and the maintainers of this package because it's an open source package, most likely. So if someone is really diligent and is actually providing this documentation, it's great and it's going to be there. But if it's not there, you can't really use this as a guideline that there are no problems with it just because no one was aware enough of these problems to put them down. So again, it's...

Speaker 3 [39:16]

Yeah, so I think we got a lot of work to do on this topic. There are several questions about scanners, linters, does rough or supporters. So I would just condense this question with how would you automate things? Just like do you use pre-commit hooks? What do you use in your CACD just to cover these issues?

Speaker 2 [39:42]

And the basic answer would be that no one is going to limit you on just one scanner. You can just put them all together, you can use multiple security scanners, you can technically use multiple linters, but you should actually configure them that they are all formatting the same way, or they're just going to fight each other. But no one is limiting you really on the amount of linters or scanners you can do. And as I touched up upon, you should, if you're trying to publish this code to other people, automate it in some kind of CI CD pipeline. And GitHub and GitLab both are giving you many tools to actually do this. So it's a good idea to just check them out. They are examples for them that you can easily adapt. I myself didn't really do many GitHub actions before because we are internally working with GitLab. So this is one of my first GitHub actions, but it was very easy to just find these basic parts that I just can put together. So just try it out.

Speaker 3 [40:46]

Great. So do you have your favorite tools you're using?

Speaker 1 [40:50]

I actually use pip tools and pip audit, pip compile for my things. But yeah, everyone should check out what's good for there. A tip maybe, there's also one, I think, dependency scanner, which is for conda actually also, because most of the scanners don't really support conda environments, but there are things out there. Cool.

Speaker 3 [41:11]

Cool. Yeah. And one listener says, oh, I tried linting, but there are so many warnings. So how do I know which warning is really critical and which should I fix first?

Speaker 2 [41:29]

If you are getting that many warnings, maybe you should work over all of them, kind of. But most linters are differentiating between warnings and errors. So if they are still warnings, it's most likely things that are not going to stop your code. They are not going to make or break things. Like the bandit scanner did severity classification, low, medium, and high. And so, basically, every scanner does this internal ranking, what's really a problem and what's just, yeah, it's okay, but you shouldn't do this. Okay.

Speaker 3 [42:10]

So there's also, the question was, why I just call it banded. Does banded also provide the CVE information? So which CVE is related to the warning or the error? Yes, no?

Speaker 2 [42:25]

I think it was there. It should have been there. That was a small CVE number. Just one sec.

Speaker 3 [42:35]

And as we're waiting for the answer, I just want to pass also many thanks from Slido for this interesting talk. It was wonderful. And one is interested in how did you do the presentation with which technique?

Speaker 1 [42:50]

Streamlit.

Speaker 3 [42:51]

Streamlit. So streamlit. So thank you very much for this interesting talk. Again, applause. Applause. Hope to see you. And you can, of course, ask them also questions afterwards.

Antonia Scherz

Antonia Scherz is senior specialist for machine learning applications at PD - Berater der öffentlichen Hand in Berlin. At PD she builds proof of concept tools and assists in software development for machine learning applications in public administration. She is passionate about making machine learning and open software tools widely and securely used by public administration and is fascinated by how new tools can be integrated into old structures for the public good.

Roman Krafft

Roman Krafft has been employed at PD - Consultant of the Public Sector GmbH since June 2021 and has worked there as a senior specialist since October 2023. He oversees projects in the strategic administrative modernization division with a focus on software development and machine learning.

Roman Krafft studied computer science (Bachelor of Science degree) at the Technical University of Kaiserslautern from 2014 to 2018 and then studied computer science (Master of Science degree) at the same university from 2018 to 2021.

Social card for talk: You shall not pass! 🧙 Strengthen your python code against attacks.