diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml
index d05ffaa288ff1241e7792c2824be1c3398020dca..c20fcb14a44050389deb53c3bb6a20ac25143530 100644
--- a/.github/workflows/build-docs.yml
+++ b/.github/workflows/build-docs.yml
@@ -9,6 +9,9 @@ on:
     paths:
       - 'docs**/'
       - '.github/workflows/build-docs.yml'
+permissions:
+  contents: read
+
 jobs:
   build-documentation:
     name: docs
diff --git a/.github/workflows/build-gluon.yml b/.github/workflows/build-gluon.yml
index 141d6d83e90832a55ffaaa082194736424b60e8e..561ff0ccca105c367a65d7d72ad59adb5c96c2d5 100644
--- a/.github/workflows/build-gluon.yml
+++ b/.github/workflows/build-gluon.yml
@@ -8,8 +8,14 @@ on:
   pull_request:
     types: [opened, synchronize, reopened]
 
+permissions:
+  contents: read
+
 jobs:
   changed:
+    permissions:
+      contents: read  # for dorny/paths-filter to fetch a list of changed files
+      pull-requests: read  # for dorny/paths-filter to read pull requests
     runs-on: ubuntu-latest
     outputs:
       targets: ${{ steps.filter.outputs.changes }}
diff --git a/.github/workflows/check-patches.yml b/.github/workflows/check-patches.yml
index ba46d407949bb215b2d51c73055380c92e8fe580..303ef7acab2993e9fe51ed201949703f3c77acbb 100644
--- a/.github/workflows/check-patches.yml
+++ b/.github/workflows/check-patches.yml
@@ -12,6 +12,9 @@ on:
       - 'modules'
       - 'patches/**'
       - '.github/workflows/check-patches.yml'
+permissions:
+  contents: read
+
 jobs:
   check-patches:
     name: Check patches
diff --git a/.github/workflows/labels.yml b/.github/workflows/labels.yml
index 67f9302d3454f83e014512679ef1bc16e9347ed3..edd88a25fa136edcfc433098c86f5c2537b25b0b 100644
--- a/.github/workflows/labels.yml
+++ b/.github/workflows/labels.yml
@@ -4,8 +4,14 @@ on:
   # only execute base branch actions
   pull_request_target:
 
+permissions:
+  contents: read
+
 jobs:
   labels:
+    permissions:
+      contents: read  # for actions/labeler to determine modified files
+      pull-requests: write  # for actions/labeler to add labels to PRs
     runs-on: ubuntu-latest
     if: github.repository_owner == 'freifunk-gluon'
     steps:
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 8acba44af39a4d636e04f6fde8aff7eeaa549d5b..ce830eff6d3dacfd6c12fbd1b79af888642e6c3e 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -3,6 +3,9 @@ on:
   push:
   pull_request:
     types: [opened, synchronize, reopened]
+permissions:
+  contents: read
+
 jobs:
   lua:
     name: Lua