diff --git a/lib/config/decrypt.ts b/lib/config/decrypt.ts
index 65099de4aaabf9d8bdb180a6ea303438f378ed78..660965fc388a12bb29efc2742fddafb83eb1222a 100644
--- a/lib/config/decrypt.ts
+++ b/lib/config/decrypt.ts
@@ -6,6 +6,7 @@ import { maskToken } from '../util/mask';
 import { regEx } from '../util/regex';
 import { addSecretForSanitizing } from '../util/sanitize';
 import { GlobalConfig } from './global';
+import { DecryptedObject } from './schema';
 import type { RenovateConfig } from './types';
 
 export async function tryDecryptPgp(
@@ -92,8 +93,17 @@ export async function tryDecrypt(
     const decryptedObjStr = await tryDecryptPgp(privateKey, encryptedStr);
     if (decryptedObjStr) {
       try {
-        const decryptedObj = JSON.parse(decryptedObjStr);
-        const { o: org, r: repo, v: value } = decryptedObj;
+        const decryptedObj = DecryptedObject.safeParse(
+          JSON.parse(decryptedObjStr)
+        );
+        // istanbul ignore if
+        if (!decryptedObj.success) {
+          const error = new Error('config-validation');
+          error.validationError = `Could not parse decrypted config.`;
+          throw error;
+        }
+
+        const { o: org, r: repo, v: value } = decryptedObj.data;
         if (is.nonEmptyString(value)) {
           if (is.nonEmptyString(org)) {
             const orgName = org.replace(regEx(/\/$/), ''); // Strip trailing slash
diff --git a/lib/config/schema.ts b/lib/config/schema.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7a2661c3690112595faa55840ef7572843b0313e
--- /dev/null
+++ b/lib/config/schema.ts
@@ -0,0 +1,7 @@
+import { z } from 'zod';
+
+export const DecryptedObject = z.object({
+  o: z.string().optional(),
+  r: z.string().optional(),
+  v: z.string().optional(),
+});