package vault_test import ( "testing" "git.eeqj.de/sneak/secret/internal/secret" "git.eeqj.de/sneak/secret/internal/vault" "github.com/awnumar/memguard" "github.com/spf13/afero" "github.com/stretchr/testify/require" ) // TestGetSecretVersionRejectsPathTraversal verifies that GetSecretVersion // validates the secret name and rejects path traversal attempts. // This is a regression test for https://git.eeqj.de/sneak/secret/issues/13 // //nolint:paralleltest // t.Setenv in parent forbids parallel subtests func TestGetSecretVersionRejectsPathTraversal(t *testing.T) { t.Setenv(secret.EnvMnemonic, testMnemonic) t.Setenv(secret.EnvUnlockPassphrase, testPassphrase) fs := afero.NewMemMapFs() vlt, err := vault.CreateVault(fs, testStateDir, testVaultName) require.NoError(t, err) // Add a legitimate secret so the vault is set up value := memguard.NewBufferFromBytes([]byte("legitimate-secret")) err = vlt.AddSecret("legit", value, false) require.NoError(t, err) // These names contain path traversal and should be rejected maliciousNames := []string{ "../../../etc/passwd", "..%2f..%2fetc/passwd", ".secret", "../sibling-vault/secrets.d/target", "foo/../bar", "a/../../etc/passwd", } for _, name := range maliciousNames { t.Run(name, func(t *testing.T) { _, err := vlt.GetSecretVersion(name, "") require.Error(t, err, "GetSecretVersion should reject malicious name: %s", name) require.Contains(t, err.Error(), "invalid secret name", "error should indicate invalid name for: %s", name) }) } } // TestGetSecretRejectsPathTraversal verifies GetSecret (which calls // GetSecretVersion) also rejects path traversal names. func TestGetSecretRejectsPathTraversal(t *testing.T) { t.Setenv(secret.EnvMnemonic, testMnemonic) t.Setenv(secret.EnvUnlockPassphrase, testPassphrase) fs := afero.NewMemMapFs() vlt, err := vault.CreateVault(fs, testStateDir, testVaultName) require.NoError(t, err) _, err = vlt.GetSecret("../../../etc/passwd") require.Error(t, err) require.Contains(t, err.Error(), "invalid secret name") } // TestGetSecretObjectRejectsPathTraversal verifies GetSecretObject // also validates names and rejects path traversal attempts. // //nolint:paralleltest // t.Setenv in parent forbids parallel subtests func TestGetSecretObjectRejectsPathTraversal(t *testing.T) { t.Setenv(secret.EnvMnemonic, testMnemonic) t.Setenv(secret.EnvUnlockPassphrase, testPassphrase) fs := afero.NewMemMapFs() vlt, err := vault.CreateVault(fs, testStateDir, testVaultName) require.NoError(t, err) maliciousNames := []string{ "../../../etc/passwd", "foo/../bar", "a/../../etc/passwd", } for _, name := range maliciousNames { t.Run(name, func(t *testing.T) { _, err := vlt.GetSecretObject(name) require.Error(t, err, "GetSecretObject should reject: %s", name) require.Contains(t, err.Error(), "invalid secret name") }) } }