diff --git a/.gitattributes b/.gitattributes
index 42c9ffc9a1..db06916b1a 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,6 +1,7 @@
 * text=auto
 
 /.github export-ignore
+/audit export-ignore
 /benchmarks export-ignore
 /docs export-ignore
 /tests export-ignore
diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index d0e5cd4d00..1524a77a3b 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -184,6 +184,20 @@ jobs:
       - name: "Upload to Codecov"
         uses: codecov/codecov-action@v2
 
+  audit:
+    runs-on: ubuntu-latest
+
+    defaults:
+      run:
+        working-directory: audit
+
+    steps:
+      - uses: actions/checkout@v3
+
+      - run: make setup
+
+      - run: make audit
+
   benchmarks:
     runs-on: ubuntu-latest
 
diff --git a/Makefile b/Makefile
index d4012b3285..29b0bd704c 100644
--- a/Makefile
+++ b/Makefile
@@ -17,7 +17,7 @@ build: ## Build the local Docker containers
 
 .PHONY: up
 up: ## Bring up the docker-compose stack
-	docker-compose up -d
+	docker-compose up --detach
 
 .PHONY: fix
 fix: rector php-cs-fixer ## Automatic code fixes
diff --git a/audit/Makefile b/audit/Makefile
new file mode 100644
index 0000000000..a9f814dc5c
--- /dev/null
+++ b/audit/Makefile
@@ -0,0 +1,24 @@
+dcclient=$$(echo "docker-compose exec -T client")
+
+.PHONY: help
+help: ## Displays this list of targets with descriptions
+	@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(firstword $(MAKEFILE_LIST)) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[32m%-30s\033[0m %s\n", $$1, $$2}'
+
+.PHONY: setup
+setup: build ## Setup the local environment
+
+.PHONY: build
+build: ## Build the local Docker containers
+	docker-compose build --pull
+
+.PHONY: up
+up: ## Bring up the docker-compose stack
+	docker-compose up --detach
+
+.PHONY: audit
+audit: up ## Runs tests with PHPUnit
+	${dcclient} deno test --allow-net
+
+.PHONY: fmt
+fmt: up ## Runs tests with PHPUnit
+	${dcclient} deno fmt test.ts
diff --git a/audit/docker-compose.yml b/audit/docker-compose.yml
new file mode 100644
index 0000000000..f9fba61799
--- /dev/null
+++ b/audit/docker-compose.yml
@@ -0,0 +1,18 @@
+services:
+  server:
+    build:
+      context: ../
+      dockerfile: audit/server.dockerfile
+    entrypoint: 'php artisan serve --host=0.0.0.0'
+    healthcheck:
+      test: curl -f http://localhost:8000/graphql?query=%7B__typename%7D || exit 1
+      interval: 3s
+      timeout: 1s
+
+  client:
+    image: denoland/deno:1.31.3
+    working_dir: /workdir
+    volumes:
+      - ./:/workdir
+    entrypoint: /bin/bash
+    tty: true
diff --git a/audit/server.dockerfile b/audit/server.dockerfile
new file mode 100644
index 0000000000..d0c05c0ae1
--- /dev/null
+++ b/audit/server.dockerfile
@@ -0,0 +1,20 @@
+FROM php:8.1-cli
+
+WORKDIR /app
+
+COPY --from=composer /usr/bin/composer /usr/bin/composer
+
+RUN apt-get update && \
+    apt-get install --yes \
+        git \
+        rsync \
+        libzip-dev \
+        zip \
+    && docker-php-ext-install \
+        zip \
+    && rm -rf /var/lib/apt/lists/*
+
+RUN composer create-project --no-progress laravel/laravel /app
+RUN composer require --no-progress nuwave/lighthouse:dev-master
+COPY . /app/vendor/nuwave/lighthouse
+RUN php artisan vendor:publish --tag=lighthouse-schema
diff --git a/audit/test.ts b/audit/test.ts
new file mode 100644
index 0000000000..345b6b63c4
--- /dev/null
+++ b/audit/test.ts
@@ -0,0 +1,27 @@
+import { serverAudits } from "npm:graphql-http";
+
+for (
+  const audit of serverAudits({
+    url: "http://server:8000/graphql",
+  })
+) {
+  // if (audit.name !== 'MUST accept application/json and match the content-type') continue;
+  Deno.test(
+    audit.name,
+    // { sanitizeResources: false },
+    async () => {
+      const result = await audit.fn();
+      // Clean up dangling resources
+      console.log(result);
+      // if ("response" in result) {
+      //   await result.response.body?.cancel();
+      // }
+      if (result.status === "error") {
+        throw result.reason;
+      }
+      if (result.status === "warn") {
+        console.warn(result.reason); // or throw if you want full compliance (warnings are not requirements)
+      }
+    },
+  );
+}