diff --git a/lib/modules/manager/cargo/__snapshots__/extract.spec.ts.snap b/lib/modules/manager/cargo/__snapshots__/extract.spec.ts.snap
index 95a994670842be86eb567247ef3aa3526d0404d1..70efe56af7a70c3de51a96344ab5e4c6258bdade 100644
--- a/lib/modules/manager/cargo/__snapshots__/extract.spec.ts.snap
+++ b/lib/modules/manager/cargo/__snapshots__/extract.spec.ts.snap
@@ -461,6 +461,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() extracts registry ur
     "depType": "dependencies",
     "managerData": {
       "nestedVersion": true,
+      "registryName": "private-crates",
     },
     "registryUrls": [
       "https://dl.cloudsmith.io/basic/my-org/my-repo/cargo/index.git",
@@ -473,6 +474,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() extracts registry ur
     "depType": "dependencies",
     "managerData": {
       "nestedVersion": true,
+      "registryName": "mcorbin",
     },
     "registryUrls": [
       "https://github.com/mcorbin/testregistry",
@@ -499,6 +501,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() extracts registry ur
     "depType": "dependencies",
     "managerData": {
       "nestedVersion": true,
+      "registryName": "private-crates",
     },
     "registryUrls": [
       "https://dl.cloudsmith.io/basic/my-org/my-repo/cargo/index.git",
@@ -511,6 +514,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() extracts registry ur
     "depType": "dependencies",
     "managerData": {
       "nestedVersion": true,
+      "registryName": "mcorbin",
     },
     "registryUrls": [
       "https://github.com/mcorbin/testregistry",
@@ -537,6 +541,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() fails to parse cargo
     "depType": "dependencies",
     "managerData": {
       "nestedVersion": true,
+      "registryName": "private-crates",
     },
     "skipReason": "unknown-registry",
   },
@@ -547,6 +552,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() fails to parse cargo
     "depType": "dependencies",
     "managerData": {
       "nestedVersion": true,
+      "registryName": "mcorbin",
     },
     "skipReason": "unknown-registry",
   },
@@ -718,6 +724,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() ignore cargo config
     "depType": "dependencies",
     "managerData": {
       "nestedVersion": true,
+      "registryName": "private-crates",
     },
     "skipReason": "unknown-registry",
   },
@@ -728,6 +735,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() ignore cargo config
     "depType": "dependencies",
     "managerData": {
       "nestedVersion": true,
+      "registryName": "mcorbin",
     },
     "skipReason": "unknown-registry",
   },
@@ -752,6 +760,7 @@ exports[`modules/manager/cargo/extract extractPackageFile() skips unknown regist
     "depType": "dependencies",
     "managerData": {
       "nestedVersion": true,
+      "registryName": "not-listed",
     },
     "skipReason": "unknown-registry",
   },
diff --git a/lib/modules/manager/cargo/extract.spec.ts b/lib/modules/manager/cargo/extract.spec.ts
index 16d8c7b2b04ff2963f4eff2d297bb95568e2d299..6b48dc84378ea563fa55a5d3134dbff78366d002 100644
--- a/lib/modules/manager/cargo/extract.spec.ts
+++ b/lib/modules/manager/cargo/extract.spec.ts
@@ -136,6 +136,7 @@ replace-with = "private-crates"`,
           depType: 'dependencies',
           managerData: {
             nestedVersion: true,
+            registryName: 'private-crates',
           },
           registryUrls: [
             'https://dl.cloudsmith.io/basic/my-org/my-repo/cargo/index.git',
@@ -148,6 +149,7 @@ replace-with = "private-crates"`,
           depType: 'dependencies',
           managerData: {
             nestedVersion: true,
+            registryName: 'mcorbin',
           },
           registryUrls: [
             'https://dl.cloudsmith.io/basic/my-org/my-repo/cargo/index.git',
@@ -212,6 +214,7 @@ replace-with = "mcorbin"`,
           depType: 'dependencies',
           managerData: {
             nestedVersion: true,
+            registryName: 'private-crates',
           },
         },
         {
@@ -221,6 +224,7 @@ replace-with = "mcorbin"`,
           depType: 'dependencies',
           managerData: {
             nestedVersion: true,
+            registryName: 'mcorbin',
           },
         },
         {
@@ -302,6 +306,7 @@ replace-with = "mcorbin"`,
           depType: 'dependencies',
           managerData: {
             nestedVersion: true,
+            registryName: 'private-crates',
           },
           registryUrls: [
             'https://dl.cloudsmith.io/basic/my-org/my-repo/cargo/index.git',
@@ -314,6 +319,7 @@ replace-with = "mcorbin"`,
           depType: 'dependencies',
           managerData: {
             nestedVersion: true,
+            registryName: 'mcorbin',
           },
           registryUrls: ['https://github.com/mcorbin/testregistry'],
         },
@@ -437,6 +443,7 @@ replace-with = "mine"`,
           depType: 'dependencies',
           managerData: {
             nestedVersion: true,
+            registryName: 'private-crates',
           },
           skipReason: 'unknown-registry',
         },
@@ -447,6 +454,7 @@ replace-with = "mine"`,
           depType: 'dependencies',
           managerData: {
             nestedVersion: true,
+            registryName: 'mcorbin',
           },
           skipReason: 'unknown-registry',
         },
@@ -493,6 +501,7 @@ replace-with = "mcorbin"
           depType: 'dependencies',
           managerData: {
             nestedVersion: true,
+            registryName: 'private-crates',
           },
           skipReason: 'unknown-registry',
         },
@@ -503,6 +512,7 @@ replace-with = "mcorbin"
           depType: 'dependencies',
           managerData: {
             nestedVersion: true,
+            registryName: 'mcorbin',
           },
           skipReason: 'unknown-registry',
         },
diff --git a/lib/modules/manager/cargo/extract.ts b/lib/modules/manager/cargo/extract.ts
index 76ea1bdd2de440d7bc0aafd4bd8837901a067767..f71df1f2226c9d9524bd9d4e9e8b8b4d49a169f2 100644
--- a/lib/modules/manager/cargo/extract.ts
+++ b/lib/modules/manager/cargo/extract.ts
@@ -1,9 +1,6 @@
 import { logger } from '../../../logger';
-import type { SkipReason } from '../../../types';
 import { coerceArray } from '../../../util/array';
 import { findLocalSiblingOrParent, readLocalFile } from '../../../util/fs';
-import { parse as parseToml } from '../../../util/toml';
-import { CrateDatasource } from '../../datasource/crate';
 import { api as versioning } from '../../versioning/cargo';
 import type {
   ExtractConfig,
@@ -11,12 +8,15 @@ import type {
   PackageFileContent,
 } from '../types';
 import { extractLockFileVersions } from './locked-version';
+import {
+  type CargoConfig,
+  CargoConfigSchema,
+  CargoManifestSchema,
+} from './schema';
 import type {
-  CargoConfig,
-  CargoManifest,
+  CargoManagerData,
   CargoRegistries,
   CargoRegistryUrl,
-  CargoSection,
 } from './types';
 import { DEFAULT_REGISTRY_URL } from './utils';
 
@@ -28,75 +28,32 @@ function getCargoIndexEnv(registryName: string): string | null {
 }
 
 function extractFromSection(
-  parsedContent: CargoSection,
-  section: keyof CargoSection,
+  dependencies: PackageDependency<CargoManagerData>[] | undefined,
   cargoRegistries: CargoRegistries,
   target?: string,
-  depTypeOverride?: string,
 ): PackageDependency[] {
-  const deps: PackageDependency[] = [];
-  const sectionContent = parsedContent[section];
-  if (!sectionContent) {
+  if (!dependencies) {
     return [];
   }
-  Object.keys(sectionContent).forEach((depName) => {
-    let skipReason: SkipReason | undefined;
-    let currentValue = sectionContent[depName];
-    let nestedVersion = false;
-    let registryUrls: string[] | undefined;
-    let packageName: string | undefined;
-
-    if (typeof currentValue !== 'string') {
-      const version = currentValue.version;
-      const path = currentValue.path;
-      const git = currentValue.git;
-      const registryName = currentValue.registry;
-      const workspace = currentValue.workspace;
 
-      packageName = currentValue.package;
+  const deps: PackageDependency<CargoManagerData>[] = [];
 
-      if (version) {
-        currentValue = version;
-        nestedVersion = true;
-        if (registryName) {
-          const registryUrl =
-            getCargoIndexEnv(registryName) ?? cargoRegistries[registryName];
+  for (const dep of Object.values(dependencies)) {
+    let registryUrls: string[] | undefined;
 
-          if (registryUrl) {
-            if (registryUrl !== DEFAULT_REGISTRY_URL) {
-              registryUrls = [registryUrl];
-            }
-          } else {
-            skipReason = 'unknown-registry';
-          }
-        }
-        if (path) {
-          skipReason = 'path-dependency';
-        }
-        if (git) {
-          skipReason = 'git-dependency';
+    if (dep.managerData?.registryName) {
+      const registryUrl =
+        getCargoIndexEnv(dep.managerData.registryName) ??
+        cargoRegistries[dep.managerData?.registryName];
+      if (registryUrl) {
+        if (registryUrl !== DEFAULT_REGISTRY_URL) {
+          registryUrls = [registryUrl];
         }
-      } else if (path) {
-        currentValue = '';
-        skipReason = 'path-dependency';
-      } else if (git) {
-        currentValue = '';
-        skipReason = 'git-dependency';
-      } else if (workspace) {
-        currentValue = '';
-        skipReason = 'inherited-dependency';
       } else {
-        currentValue = '';
-        skipReason = 'invalid-dependency-specification';
+        dep.skipReason = 'unknown-registry';
       }
     }
-    const dep: PackageDependency = {
-      depName,
-      depType: section,
-      currentValue: currentValue as any,
-      managerData: { nestedVersion },
-      datasource: CrateDatasource.id,
-    };
+
     if (registryUrls) {
       dep.registryUrls = registryUrls;
     } else {
@@ -108,24 +65,16 @@ function extractFromSection(
       } else {
         // we always expect to have DEFAULT_REGISTRY_ID set, if it's not it means the config defines an alternative
         // registry that we couldn't resolve.
-        skipReason = 'unknown-registry';
+        dep.skipReason = 'unknown-registry';
       }
     }
 
-    if (skipReason) {
-      dep.skipReason = skipReason;
-    }
     if (target) {
       dep.target = target;
     }
-    if (packageName) {
-      dep.packageName = packageName;
-    }
-    if (depTypeOverride) {
-      dep.depType = depTypeOverride;
-    }
     deps.push(dep);
-  });
+  }
+
   return deps;
 }
 
@@ -135,12 +84,15 @@ async function readCargoConfig(): Promise<CargoConfig | null> {
     const path = `.cargo/${configName}`;
     const payload = await readLocalFile(path, 'utf8');
     if (payload) {
-      try {
-        return parseToml(payload) as CargoConfig;
-      } catch (err) {
-        logger.debug({ err }, `Error parsing ${path}`);
+      const parsedCargoConfig = CargoConfigSchema.safeParse(payload);
+      if (parsedCargoConfig.success) {
+        return parsedCargoConfig.data;
+      } else {
+        logger.debug(
+          { err: parsedCargoConfig.error, path },
+          `Error parsing cargo config`,
+        );
       }
-      break;
     }
   }
 
@@ -217,19 +169,23 @@ export async function extractPackageFile(
   content: string,
   packageFile: string,
   _config?: ExtractConfig,
-): Promise<PackageFileContent | null> {
+): Promise<PackageFileContent<CargoManagerData> | null> {
   logger.trace(`cargo.extractPackageFile(${packageFile})`);
 
   const cargoConfig = (await readCargoConfig()) ?? {};
   const cargoRegistries = extractCargoRegistries(cargoConfig);
 
-  let cargoManifest: CargoManifest;
-  try {
-    cargoManifest = parseToml(content) as CargoManifest;
-  } catch (err) {
-    logger.debug({ err, packageFile }, 'Error parsing Cargo.toml file');
+  const parsedCargoManifest = CargoManifestSchema.safeParse(content);
+  if (!parsedCargoManifest.success) {
+    logger.debug(
+      { err: parsedCargoManifest.error, packageFile },
+      'Error parsing Cargo.toml file',
+    );
     return null;
   }
+
+  const cargoManifest = parsedCargoManifest.data;
+
   /*
     There are the following sections in Cargo.toml:
     [package]
@@ -249,20 +205,17 @@ export async function extractPackageFile(
       // Dependencies for `${target}`
       const deps = [
         ...extractFromSection(
-          targetContent,
-          'dependencies',
+          targetContent.dependencies,
           cargoRegistries,
           target,
         ),
         ...extractFromSection(
-          targetContent,
-          'dev-dependencies',
+          targetContent['dev-dependencies'],
           cargoRegistries,
           target,
         ),
         ...extractFromSection(
-          targetContent,
-          'build-dependencies',
+          targetContent['build-dependencies'],
           cargoRegistries,
           target,
         ),
@@ -275,18 +228,16 @@ export async function extractPackageFile(
   let workspaceDeps: PackageDependency[] = [];
   if (workspaceSection) {
     workspaceDeps = extractFromSection(
-      workspaceSection,
-      'dependencies',
+      workspaceSection.dependencies,
       cargoRegistries,
       undefined,
-      'workspace.dependencies',
     );
   }
 
   const deps = [
-    ...extractFromSection(cargoManifest, 'dependencies', cargoRegistries),
-    ...extractFromSection(cargoManifest, 'dev-dependencies', cargoRegistries),
-    ...extractFromSection(cargoManifest, 'build-dependencies', cargoRegistries),
+    ...extractFromSection(cargoManifest.dependencies, cargoRegistries),
+    ...extractFromSection(cargoManifest['dev-dependencies'], cargoRegistries),
+    ...extractFromSection(cargoManifest['build-dependencies'], cargoRegistries),
     ...targetDeps,
     ...workspaceDeps,
   ];
diff --git a/lib/modules/manager/cargo/schema.ts b/lib/modules/manager/cargo/schema.ts
index 4e73235f60cf33f5bebdf14ec628025167a2b083..52640d4252d8937492c26353962c8f986ea12bec 100644
--- a/lib/modules/manager/cargo/schema.ts
+++ b/lib/modules/manager/cargo/schema.ts
@@ -1,5 +1,133 @@
 import { z } from 'zod';
-import { Toml } from '../../../util/schema-utils';
+import type { SkipReason } from '../../../types';
+import { Toml, withDepType } from '../../../util/schema-utils';
+import { CrateDatasource } from '../../datasource/crate';
+import type { PackageDependency } from '../types';
+import type { CargoManagerData } from './types';
+
+const CargoDep = z.union([
+  z
+    .object({
+      /** Path on disk to the crate sources */
+      path: z.string().optional(),
+      /** Git URL for the dependency */
+      git: z.string().optional(),
+      /** Semver version */
+      version: z.string().optional(),
+      /** Name of a registry whose URL is configured in `.cargo/config.toml` or `.cargo/config` */
+      registry: z.string().optional(),
+      /** Name of a package to look up */
+      package: z.string().optional(),
+      /** Whether the dependency is inherited from the workspace */
+      workspace: z.boolean().optional(),
+    })
+    .transform(
+      ({
+        path,
+        git,
+        version,
+        registry,
+        package: pkg,
+        workspace,
+      }): PackageDependency<CargoManagerData> => {
+        let skipReason: SkipReason | undefined;
+        let currentValue: string | undefined;
+        let nestedVersion = false;
+
+        if (version) {
+          currentValue = version;
+          nestedVersion = true;
+        } else {
+          currentValue = '';
+          skipReason = 'invalid-dependency-specification';
+        }
+
+        if (path) {
+          skipReason = 'path-dependency';
+        } else if (git) {
+          skipReason = 'git-dependency';
+        } else if (workspace) {
+          skipReason = 'inherited-dependency';
+        }
+
+        const dep: PackageDependency<CargoManagerData> = {
+          currentValue,
+          managerData: { nestedVersion },
+          datasource: CrateDatasource.id,
+        };
+
+        if (skipReason) {
+          dep.skipReason = skipReason;
+        }
+        if (pkg) {
+          dep.packageName = pkg;
+        }
+        if (registry) {
+          dep.managerData!.registryName = registry;
+        }
+
+        return dep;
+      },
+    ),
+  z.string().transform(
+    (version): PackageDependency<CargoManagerData> => ({
+      currentValue: version,
+      managerData: { nestedVersion: false },
+      datasource: CrateDatasource.id,
+    }),
+  ),
+]);
+
+const CargoDeps = z.record(z.string(), CargoDep).transform((record) => {
+  const deps: PackageDependency[] = [];
+
+  for (const [depName, dep] of Object.entries(record)) {
+    dep.depName = depName;
+    deps.push(dep);
+  }
+
+  return deps;
+});
+
+export type CargoDeps = z.infer<typeof CargoDeps>;
+
+const CargoSection = z.object({
+  dependencies: withDepType(CargoDeps, 'dependencies').optional(),
+  'dev-dependencies': withDepType(CargoDeps, 'dev-dependencies').optional(),
+  'build-dependencies': withDepType(CargoDeps, 'build-dependencies').optional(),
+});
+
+const CargoWorkspace = z.object({
+  dependencies: withDepType(CargoDeps, 'workspace.dependencies').optional(),
+});
+
+const CargoTarget = z.record(z.string(), CargoSection);
+
+export const CargoManifestSchema = Toml.pipe(
+  CargoSection.extend({
+    package: z.object({ version: z.string().optional() }).optional(),
+    workspace: CargoWorkspace.optional(),
+    target: CargoTarget.optional(),
+  }),
+);
+
+const CargoConfigRegistry = z.object({
+  index: z.string().optional(),
+});
+
+const CargoConfigSource = z.object({
+  'replace-with': z.string().optional(),
+  registry: z.string().optional(),
+});
+
+export const CargoConfigSchema = Toml.pipe(
+  z.object({
+    registries: z.record(z.string(), CargoConfigRegistry).optional(),
+    source: z.record(z.string(), CargoConfigSource).optional(),
+  }),
+);
+
+export type CargoConfig = z.infer<typeof CargoConfigSchema>;
 
 const CargoLockPackageSchema = z.object({
   name: z.string(),
diff --git a/lib/modules/manager/cargo/types.ts b/lib/modules/manager/cargo/types.ts
index b28c3ced50fa27c1684053a17286b8d8e923df9d..d2e3f940493373b8b6d0a7357245c253d969049f 100644
--- a/lib/modules/manager/cargo/types.ts
+++ b/lib/modules/manager/cargo/types.ts
@@ -1,53 +1,5 @@
 import type { DEFAULT_REGISTRY_URL } from './utils';
 
-export interface CargoPackage {
-  /** Semver version */
-  version: string;
-}
-
-export interface CargoDep {
-  /** Path on disk to the crate sources */
-  path?: string;
-  /** Git URL for the dependency */
-  git?: string;
-  /** Semver version */
-  version?: string;
-  /** Name of a registry whose URL is configured in `.cargo/config.toml` */
-  registry?: string;
-  /** Name of a package to look up */
-  package?: string;
-  /** Whether the dependency is inherited from the workspace*/
-  workspace?: boolean;
-}
-
-export type CargoDeps = Record<string, CargoDep | string>;
-
-export interface CargoSection {
-  dependencies?: CargoDeps;
-  'dev-dependencies'?: CargoDeps;
-  'build-dependencies'?: CargoDeps;
-}
-
-export interface CargoManifest extends CargoSection {
-  target?: Record<string, CargoSection>;
-  workspace?: CargoSection;
-  package?: CargoPackage;
-}
-
-export interface CargoConfig {
-  registries?: Record<string, CargoRegistry>;
-  source?: Record<string, CargoSource>;
-}
-
-export interface CargoRegistry {
-  index?: string;
-}
-
-export interface CargoSource {
-  'replace-with'?: string;
-  registry?: string;
-}
-
 /**
  * null means a registry was defined, but we couldn't find a valid URL
  */
@@ -55,3 +7,8 @@ export type CargoRegistryUrl = string | typeof DEFAULT_REGISTRY_URL | null;
 export interface CargoRegistries {
   [key: string]: CargoRegistryUrl;
 }
+
+export interface CargoManagerData {
+  nestedVersion?: boolean;
+  registryName?: string;
+}
diff --git a/lib/modules/manager/poetry/schema.ts b/lib/modules/manager/poetry/schema.ts
index ac5c7e741c293a2f397cd025add785dae98afabb..25735dc3ff865482294d380bcbdf827aceaf67c6 100644
--- a/lib/modules/manager/poetry/schema.ts
+++ b/lib/modules/manager/poetry/schema.ts
@@ -1,9 +1,13 @@
-import type { ZodEffects, ZodType, ZodTypeDef } from 'zod';
 import { z } from 'zod';
 import { logger } from '../../../logger';
 import { parseGitUrl } from '../../../util/git/url';
 import { regEx } from '../../../util/regex';
-import { LooseArray, LooseRecord, Toml } from '../../../util/schema-utils';
+import {
+  LooseArray,
+  LooseRecord,
+  Toml,
+  withDepType,
+} from '../../../util/schema-utils';
 import { uniq } from '../../../util/uniq';
 import { GitRefsDatasource } from '../../datasource/git-refs';
 import { GitTagsDatasource } from '../../datasource/git-tags';
@@ -172,18 +176,6 @@ export const PoetryDependencies = LooseRecord(
   return deps;
 });
 
-function withDepType<
-  Output extends PackageDependency[],
-  Schema extends ZodType<Output, ZodTypeDef, unknown>,
->(schema: Schema, depType: string): ZodEffects<Schema> {
-  return schema.transform((deps) => {
-    for (const dep of deps) {
-      dep.depType = depType;
-    }
-    return deps;
-  });
-}
-
 export const PoetryGroupDependencies = LooseRecord(
   z.string(),
   z
diff --git a/lib/util/schema-utils.ts b/lib/util/schema-utils.ts
index 4a1c35d98d6d3f73b372d232a7a8b37e001c8a8d..f5a12c54095685ce48bd2ae74dedd1c90141c8f6 100644
--- a/lib/util/schema-utils.ts
+++ b/lib/util/schema-utils.ts
@@ -2,7 +2,8 @@ import JSON5 from 'json5';
 import * as JSONC from 'jsonc-parser';
 import { DateTime } from 'luxon';
 import type { JsonArray, JsonValue } from 'type-fest';
-import { z } from 'zod';
+import { type ZodEffects, type ZodType, type ZodTypeDef, z } from 'zod';
+import type { PackageDependency } from '../modules/manager/types';
 import { parse as parseToml } from './toml';
 import { parseSingleYaml, parseYaml } from './yaml';
 
@@ -263,3 +264,15 @@ export const Toml = z.string().transform((str, ctx) => {
     return z.NEVER;
   }
 });
+
+export function withDepType<
+  Output extends PackageDependency[],
+  Schema extends ZodType<Output, ZodTypeDef, unknown>,
+>(schema: Schema, depType: string): ZodEffects<Schema> {
+  return schema.transform((deps) => {
+    for (const dep of deps) {
+      dep.depType = depType;
+    }
+    return deps;
+  });
+}