AI-generated code and the problem of ambient permissions

Posted: (EET/GMT+2)

 

Happy August! A new month is a nice moment to start thinking about the architecture we use in our systems. As we know, AI can now generate code faster than we can review it.

That raises the normal secure coding questions, but also a more basic one: why does the code get so much authority when it runs?

Generated code may have bugs, insecure assumptions, missing validation, or unsafe dependency choices. These are familiar problems. We can review the code, scan it, test it, and ask the AI to explain what it changed.

But there is another layer below that. When a normal application runs on Windows or Linux, it often runs with the permissions of the current user. If the user can read the project folder, write files, access environment variables, and open network connections, the application usually can too.

That is called ambient authority. The application did not ask for each permission separately. It inherited a broad execution context and can use whatever that context already allows.

This has been the normal desktop and server model for a long time. It is convenient, and it keeps old applications working. But it is not a great default when unknown or generated code is executed quickly.

The safer principle is least privilege: give the process only the access it needs for the task. For generated code, a better default would often be:

  • no network access unless required
  • read-only access to source code unless writes are needed
  • no access to user profile secrets by default
  • no access to production databases
  • no package installation without review
  • short-lived credentials instead of broad developer credentials.

This is where containers (see for example Microsoft AppContainer isolation) can help, even for simple local checks. For example, run tests inside a container with no network and a read-only source mount in Docker:

docker run --rm ^
    --network none ^
    -v "%cd%:/work:ro" ^
    mcr.microsoft.com/dotnet/sdk:10.0 ^
    dotnet test /work

This does not make the code automatically secure. It only reduces what the code can touch while it runs. The idea is simple: reduce the blast radius before running generated code, not only after finding a problem.

If the task needs write access, use a disposable folder:

mkdir C:\Temp\AiWork
robocopy . C:\Temp\AiWork /MIR

docker run --rm ^
    --network none ^
    -v "C:\Temp\AiWork:/work" ^
    mcr.microsoft.com/dotnet/sdk:10.0 ^
    dotnet test /work

Now the generated code can modify the temporary copy, not the original working tree. For scripts, the same idea applies. Do not run generated PowerShell or Bash directly against important folders, real credentials, or production systems.

Use a smaller working directory. Pass inputs explicitly. Keep secrets out of the environment unless the script really needs them.

A useful mental model is:

Generated code should be treated like downloaded code until it has been reviewed and constrained.

Security tools and AI guardrails are still useful. Code reviewing, static analysis, bill-of-materials analysis and dependency scanning all still matter. But those tools are compensating controls. They try to detect problems after the code has already been written.

The operating environment should also help by limiting what the code can do if the review misses something.

As a tip, I have found that asking these three questions before running generated code helps:

  • What files can this application read?
  • What files can this application write?
  • What network or credentials can this application use?

If the answer is "everything my user account can access", the code probably has more authority than the task really needs. The principle of least privilege is the one to keep in mind.

Of course, this is not only an AI problem. AI just makes the old problem more visible. We are now creating and executing more code, faster, with less time to understand every line.

The default should move closer to deny all, then allow what the task needs.

Until our tools make that easy, we can still build the habit ourselves: run generated code in small folders, with small permissions, and with clear boundaries.