logo

Database

Excessive privileges - Access Mode

Need

Creation of sensitive files with owner-only permissions

Context

• Usage of Elixir 1.15+ on Unix-like systems for building application services

• Usage of the File module for storing secrets on disk

Description

1. Non compliant code

defmodule MyApp.TokenStore do
  @path "/var/lib/my_app/token"

  def store_token(token) do
    File.write!(@path, token)
    File.chmod!(@path, 0o666)
  end
end

The `store_token/1` function below writes an API token to disk and then calls `File.chmod/2` with mode `0o666`. Mode `0o666` gives read and write access to every user on the host. Any other local account, a compromised process running as another user or a container that shares the volume can read the token and use it, or overwrite it to lock the application out. `0o777` on directories is worse, because it also lets anyone create or delete files inside them. `:file.change_mode/2` with the same values has the same effect.

2. Steps

• Create files that hold secrets or personal data with mode `0o600`, and their directories with `0o700`.

• Never pass world-readable or world-writable modes such as `0o666`, `0o777` or `0o707` to `File.chmod/2` or `:file.change_mode/2`.

• Restrict the permissions before writing the secret, not after.

• Grant access to other services through a dedicated group with a mode such as `0o640`.

• Run the application with a restrictive umask, such as `0o077`, as a second layer of defense.

3. Secure code example

defmodule MyApp.TokenStore do
  @dir "/var/lib/my_app/secrets"
  @path Path.join(@dir, "token")

  def store_token(token) do
    File.mkdir_p!(@dir)
    File.chmod!(@dir, 0o700)
    File.touch!(@path)...

The corrected function keeps the token in a directory that only the application user can open, with mode `0o700`, and restricts the file itself to `0o600`, read and write for the owner only. The order matters. The file is created empty with `File.touch!/1` and restricted with `File.chmod!/2` before the token is written, so there is no moment in which the secret sits in a file with the default, broader permissions. Other services that need the token should receive access through a dedicated group with the narrowest mode that works, such as `0o640`, never through world permissions.