diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 107013e39cfb28daccd81bf4accb14fdc1b9d874..b75fa62e4dd84a0137600d9f71aa5c62a61b1b34 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -24,12 +24,14 @@ build:
 test_success:
   stage: test
   script:
-    - docker run ${TEST_IMAGE} ./reproduce.py release-1.0.1
+  # Consider adding the cap and the device directly to the CI config
+  # https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-docker-section
+    - docker run --cap-add SYS_ADMIN --device /dev/fuse ${TEST_IMAGE} ./reproduce.py release-1.0.1
 
 test_failure:
   stage: test
   script:
-    - if docker run ${TEST_IMAGE} ./reproduce.py release-1.0.3; then exit 1; else exit 0; fi
+    - if docker run --cap-add SYS_ADMIN --device /dev/fuse ${TEST_IMAGE} ./reproduce.py release-1.0.3; then exit 1; else exit 0; fi
 
 release:
   stage: release
diff --git a/README.md b/README.md
index 06b1f4e37e2c25fcf4dc14e5120f3a4062b90055..6019ef213d3153b82dd0367214915fd90894374e 100644
--- a/README.md
+++ b/README.md
@@ -72,12 +72,22 @@ Build our Docker image:
 
 ### Run the verification
 
+Currently, the verification needs `disorderfs` as a deterministic file-system.
+Therefore, please make sure that `fuse` is installed on your host system.
+
+    apt install fuse
+
 To verify a specific version of Briar, run
 
-    docker run briar/reproducer:latest ./reproduce.py [tag]
+    docker run --cap-add SYS_ADMIN --device /dev/fuse briar/reproducer:latest ./reproduce.py [tag]
 
 Where `[tag]` is the git tag (source code snapshot) that identifies the version
 you want to test, for example `release-1.0.1`.
 
 You can find a list of tags in Briar's
 [source code repository](https://code.briarproject.org/akwizgran/briar/tags).
+
+The `SYS_ADMIN` capability and the `fuse` device are required,
+so the container can build the app inside a `disorderfs`.
+We hope to be able to drop this requirement
+once this [upstream issue](https://issuetracker.google.com/issues/110237303) is fixed.
\ No newline at end of file
diff --git a/install-dependencies.sh b/install-dependencies.sh
index 4afd8b4e6a41762e392540b3a9d49347280ee823..ef0574e5208985eb5e4f8b0089ce9f2fe2410f64 100755
--- a/install-dependencies.sh
+++ b/install-dependencies.sh
@@ -5,5 +5,7 @@ set -x
 apt-get install -y --no-install-recommends \
 	git \
 	default-jdk-headless \
+	fuse \
+	disorderfs \
 	unzip \
 	wget
diff --git a/reproduce.py b/reproduce.py
index c2479fc24ef3ad7e4e87813da030672246be19cb..e48eb00a25af63b8fff7a334a78e8dbc76468992 100755
--- a/reproduce.py
+++ b/reproduce.py
@@ -1,13 +1,14 @@
 #!/usr/bin/env python3
 
 import os
-import subprocess
+from subprocess import call, check_call, check_output
 import sys
 
 REPO_DIR = "briar"
 REFERENCE_URL = 'https://briarproject.org/apk/briar-%s.apk'
 GRADLE_TASK = "briar-android:assembleRelease"
 APK_PATH = "briar-android/build/outputs/apk/release/briar-android-release-unsigned.apk"
+BUILD_DIR = "briar-build"
 
 
 def main():
@@ -22,14 +23,19 @@ def main():
     version = tag.split('-')[1]
     url = REFERENCE_URL % version
     reference_apk = "briar-%s.apk" % version
-    subprocess.check_call(['wget', '--no-verbose', url, '-O', reference_apk])
+    check_call(['wget', '--no-verbose', url, '-O', reference_apk])
+
+    # use deterministic file system for building the app
+    if not os.path.exists(BUILD_DIR):
+        os.makedirs(BUILD_DIR)
+    check_call(['disorderfs', '--sort-dirents=yes', '--reverse-dirents=no', REPO_DIR, BUILD_DIR])
 
     # build the app
-    repo_call(["./gradlew", "--no-daemon", GRADLE_TASK])
+    check_call(["./gradlew", "--no-daemon", GRADLE_TASK], cwd=BUILD_DIR)
 
     # check if both APKs match
-    apk = os.path.join(REPO_DIR, APK_PATH)
-    if subprocess.call(['./verify-apk.py', reference_apk, apk]) == 0:
+    apk = os.path.join(BUILD_DIR, APK_PATH)
+    if call(['./verify-apk.py', reference_apk, apk]) == 0:
         print("Version '%s' was built reproducible! :)" % tag)
         sys.exit(0)
     else:
@@ -44,7 +50,7 @@ def prepare_repo(tag):
         repo_call(['git', 'checkout', '-f', 'master'])
     else:
         # clone repo
-        subprocess.check_call(['git', 'clone', os.environ.get("REPO_URL"), REPO_DIR])
+        check_call(['git', 'clone', os.environ.get("REPO_URL"), REPO_DIR])
 
     # undo all changes
     repo_call(['git', 'reset', '--hard'])
@@ -54,7 +60,7 @@ def prepare_repo(tag):
 
     # use latest tag if none given
     if tag is None:
-        result = subprocess.check_output(['git', 'describe', '--abbrev=0', '--tags'], cwd=REPO_DIR)
+        result = check_output(['git', 'describe', '--abbrev=0', '--tags'], cwd=REPO_DIR)
         tag = result.decode().rstrip()  # strip away line-break
 
     # checkout tag
@@ -65,7 +71,7 @@ def prepare_repo(tag):
 
 
 def repo_call(command):
-    subprocess.check_call(command, cwd=REPO_DIR)
+    check_call(command, cwd=REPO_DIR)
 
 
 def fail(msg=""):