diff --git a/config.go b/config.go
index b89c7ae..ea0fde1 100644
--- a/config.go
+++ b/config.go
@@ -3,8 +3,11 @@ package main
 import (
 	"context"
 	"errors"
+	"fmt"
 	"os"
 	"path"
+	"reflect"
+	"slices"
 	"time"
 
 	"github.com/prometheus/client_golang/prometheus"
@@ -32,6 +35,11 @@ var (
 		Name: "git_mirror_config_last_reload_success_timestamp_seconds",
 		Help: "Timestamp of the last successful configuration reload.",
 	})
+	allowedRepoPoolConfig = getAllowedKeys(mirror.RepoPoolConfig{})
+	allowedDefaults       = getAllowedKeys(mirror.DefaultConfig{})
+	allowedAuthKeys       = getAllowedKeys(mirror.Auth{})
+	allowedRepoKeys       = getAllowedKeys(mirror.RepositoryConfig{})
+	allowedWorktreeKeys   = getAllowedKeys(mirror.WorktreeConfig{})
 )
 
 // WatchConfig polls the config file every interval and reloads if modified
@@ -174,14 +182,132 @@ func parseConfigFile(path string) (*mirror.RepoPoolConfig, error) {
 	if err != nil {
 		return nil, err
 	}
+
+	err = validateConfigYaml([]byte(yamlFile))
+	if err != nil {
+		return nil, err
+	}
+
 	conf := &mirror.RepoPoolConfig{}
 	err = yaml.Unmarshal(yamlFile, conf)
 	if err != nil {
 		return nil, err
 	}
+
 	return conf, nil
 }
 
+func validateConfigYaml(yamlData []byte) error {
+	var raw map[string]interface{}
+	if err := yaml.Unmarshal(yamlData, &raw); err != nil {
+		return err
+	}
+
+	// check all root config sections for unexpected keys
+	if key := findUnexpectedKey(raw, allowedRepoPoolConfig); key != "" {
+		return fmt.Errorf("unexpected key: .%v", key)
+	}
+
+	// check ".defaults" if it's not empty
+	if raw["defaults"] != nil {
+		defaultsMap, ok := raw["defaults"].(map[string]interface{})
+		if !ok {
+			return fmt.Errorf(".defaults config is not valid")
+		}
+
+		if key := findUnexpectedKey(defaultsMap, allowedDefaults); key != "" {
+			return fmt.Errorf("unexpected key: .defaults.%v", key)
+		}
+
+		// check ".defaults.auth"
+		if authMap, ok := defaultsMap["auth"].(map[string]interface{}); ok {
+			if key := findUnexpectedKey(authMap, allowedAuthKeys); key != "" {
+				return fmt.Errorf("unexpected key: .defaults.auth.%v", key)
+			}
+		}
+	}
+
+	// skip further config checks if ".repositories" is empty
+	if raw["repositories"] == nil {
+		return nil
+	}
+
+	// check ".repositories"
+	reposInterface, ok := raw["repositories"].([]interface{})
+	if !ok {
+		return fmt.Errorf(".repositories config must be an array")
+	}
+
+	// check each repository in ".repositories"
+	for _, repoInterface := range reposInterface {
+		repoMap, ok := repoInterface.(map[string]interface{})
+		if !ok {
+			return fmt.Errorf(".repositories config is not valid")
+		}
+
+		if key := findUnexpectedKey(repoMap, allowedRepoKeys); key != "" {
+			return fmt.Errorf("unexpected key: .repositories[%v].%v", repoMap["remote"], key)
+		}
+
+		// skip further repository checks if "worktrees" is empty
+		if repoMap["worktrees"] == nil {
+			continue
+		}
+
+		// check "worktrees" in each repository
+		worktreesInterface, ok := repoMap["worktrees"].([]interface{})
+		if !ok {
+			return fmt.Errorf("worktrees config must be an array in .repositories[%v]", repoMap["remote"])
+		}
+
+		for i, worktreeInterface := range worktreesInterface {
+			worktreeMap, ok := worktreeInterface.(map[string]interface{})
+			if !ok {
+				return fmt.Errorf("worktrees config is not valid in .repositories[%v]", repoMap["remote"])
+			}
+
+			if key := findUnexpectedKey(worktreeMap, allowedWorktreeKeys); key != "" {
+				return fmt.Errorf("unexpected key: .repositories[%v].worktrees[%v].%v", repoMap["remote"], i, key)
+			}
+
+			// Check "pathspecs" in each worktree
+			if pathspecsInterface, exists := worktreeMap["pathspecs"]; exists {
+				if _, ok := pathspecsInterface.([]interface{}); !ok {
+					return fmt.Errorf("pathspecs config must be an array in .repositories[%v].worktrees[%v]", repoMap["remote"], i)
+				}
+			}
+		}
+	}
+
+	return nil
+}
+
+// getAllowedKeys retrieves a list of allowed keys from the specified struct
+func getAllowedKeys(config interface{}) []string {
+	var allowedKeys []string
+	val := reflect.ValueOf(config)
+	typ := reflect.TypeOf(config)
+
+	for i := 0; i < val.NumField(); i++ {
+		field := typ.Field(i)
+		yamlTag := field.Tag.Get("yaml")
+		if yamlTag != "" {
+			allowedKeys = append(allowedKeys, yamlTag)
+		}
+	}
+	return allowedKeys
+}
+
+func findUnexpectedKey(raw map[string]interface{}, allowedKeys []string) string {
+	for key := range raw {
+		if !slices.Contains(allowedKeys, key) {
+			return key
+		}
+	}
+
+	return ""
+}
+
 // diffRepositories will do the diff between current state and new config and
 // return new repositories config and list of remote url which are not found in config
 func diffRepositories(repoPool *mirror.RepoPool, newConfig *mirror.RepoPoolConfig) (
diff --git a/config_test.go b/config_test.go
index a8b77bf..4f176e1 100644
--- a/config_test.go
+++ b/config_test.go
@@ -11,7 +11,6 @@ import (
 )
 
 func Test_diffRepositories(t *testing.T) {
-
 	tests := []struct {
 		name             string
 		initialConfig    *mirror.RepoPoolConfig
@@ -199,7 +198,6 @@ func Test_diffWorktrees(t *testing.T) {
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
-
 			if err := tt.initialRepoConf.PopulateEmptyLinkPaths(); err != nil {
 				t.Fatalf("failed to create repo error = %v", err)
 			}
@@ -234,3 +232,181 @@ func Test_diffWorktrees(t *testing.T) {
 		})
 	}
 }
+
+func Test_validateConfigYaml(t *testing.T) {
+	tests := []struct {
+		name      string
+		yamlData  []byte
+		wantError bool
+	}{
+		{
+			name: "valid - full config",
+			yamlData: []byte(`
+defaults:
+  root: /tmp/git-mirror
+  link_root: /tmp/links
+  interval: 30s
+  mirror_timeout: 2m
+  git_gc: always
+  auth:
+    ssh_key_path: /etc/git-secret/ssh
+    ssh_known_hosts_path: /etc/git-secret/known_hosts
+
+repositories:
+  - remote: https://github.com/utilitywarehouse/git-mirror
+    worktrees:
+      - link: aaa
+        ref: main
+      - link: bbb
+        ref: main
+  - remote: https://github.com/utilitywarehouse/another-repo
+    root: /some/other/location
+    link_root: /some/path
+    interval: 1m
+    mirror_timeout: 5m
+    git_gc: always
+    auth:
+      ssh_key_path: /some/other/location
+      ssh_known_hosts_path: /some/other/location
+    worktrees:
+      - link: alerts
+        ref: main
+        pathspecs:
+          - path
+          - path2/*.yaml
+`),
+			wantError: false,
+		},
+		{
+			name: "valid - empty config",
+			yamlData: []byte(`
+`),
+			wantError: false,
+		},
+		{
+			name: "valid - defaults config only",
+			yamlData: []byte(`
+defaults:
+`),
+			wantError: false,
+		},
+		{
+			name: "valid - repositories config only",
+			yamlData: []byte(`
+repositories:
+`),
+			wantError: false,
+		},
+		{
+			name: "invalid - unexpected key",
+			yamlData: []byte(`
+not-valid:
+  test: test
+
+defaults:
+  root: /tmp/git-mirror
+
+repositories:
+  - remote: https://github.com/utilitywarehouse/git-mirror
+`),
+			wantError: true,
+		},
+		{
+			name: "invalid - unexpected key in defaults",
+			yamlData: []byte(`
+defaults:
+  root: /tmp/git-mirror
+  not_valid: test
+
+repositories:
+  - remote: https://github.com/utilitywarehouse/git-mirror
+`),
+			wantError: true,
+		},
+		{
+			name: "invalid - unexpected key in auth",
+			yamlData: []byte(`
+defaults:
+  root: /tmp/git-mirror
+  auth:
+    not_valid: test
+
+repositories:
+  - remote: https://github.com/utilitywarehouse/git-mirror
+`),
+			wantError: true,
+		},
+		{
+			name: "invalid - unexpected key in repositories",
+			yamlData: []byte(`
+defaults:
+  root: /tmp/git-mirror
+
+repositories:
+  - remote: https://github.com/utilitywarehouse/git-mirror
+    not_valid: test
+`),
+			wantError: true,
+		},
+		{
+			name: "invalid - unexpected key in repository worktrees",
+			yamlData: []byte(`
+defaults:
+  root: /tmp/git-mirror
+
+repositories:
+  - remote: https://github.com/utilitywarehouse/git-mirror
+    worktrees:
+      - link: aaa
+        not_valid: test
+`),
+			wantError: true,
+		},
+		{
+			name: "invalid - repositories is not an array",
+			yamlData: []byte(`
+defaults:
+  root: /tmp/git-mirror
+
+repositories: https://github.com/utilitywarehouse/git-mirror
+`),
+			wantError: true,
+		},
+		{
+			name: "invalid - worktrees is not an array",
+			yamlData: []byte(`
+defaults:
+  root: /tmp/git-mirror
+
+repositories:
+  - remote: https://github.com/utilitywarehouse/git-mirror
+    worktrees: test
+`),
+			wantError: true,
+		},
+		{
+			name: "invalid - pathspecs is not an array",
+			yamlData: []byte(`
+defaults:
+  root: /tmp/git-mirror
+
+repositories:
+  - remote: https://github.com/utilitywarehouse/git-mirror
+    worktrees:
+      - link: aaa
+        not_valid: test
+        pathspecs: readme.md
+`),
+			wantError: true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			err := validateConfigYaml(tt.yamlData)
+			if (err != nil) != tt.wantError {
+				t.Errorf("validateConfigYaml() error = %v, wantError %v", err, tt.wantError)
+			}
+		})
+	}
+}