Skip to main content

Iโ€™ll be honest, when I first started working with .NET, I didnโ€™t think much about secrets management. Hardcoding an API key or a database connection string in a config file felt harmless. But one day, I accidentally pushed a repository with a hardcoded key to GitHub. Within minutes, bots had scanned it, and the key was compromised.

That was my wake-up call. I quickly learned that secrets leakage is one of the most common security mistakes developers makeโ€”and attackers know it. They constantly scan public and private repositories looking for credentials that could grant them access to systems, databases, or third-party APIs.

But hereโ€™s the thing: even if your repository is private, your secrets arenโ€™t necessarily safe.

Reverse Engineering: A Hidden Risk

Attackers donโ€™t always need access to your source code to steal secrets. With reverse engineering, they can decompile compiled applications and extract credentials directly from binaries.

  • .NET assemblies (.dll, .exe) can be decompiled with tools like dnSpy, ILSpy, or JetBrains dotPeek to reveal hardcoded secrets.
  • Mobile applications (.apk) can be decompiled and inspected to extract API keys and tokens.
  • Web applications can expose secrets through client-side JavaScript or misconfigured APIs.

Even if you never push a secret to a repository, if itโ€™s embedded in your application, it can still be stolen.

How Do We Prevent This?

  • Detect secrets before they get into source control or production.
  • Automatically extract secrets and replace them with secure references.
  • Store and manage secrets in an encrypted vault.

In this guide, Iโ€™ll walk you through how to detect secrets in your .NET project at build time, extract them securely, and manage them properly using industry best practices.

Index

Secret Detection in .NET During Build Time

Hardcoded secrets are one of the biggest security risks in software development. Whether it’s an API key, database connection string, or cryptographic token, leaving sensitive credentials in your source code can lead to serious vulnerabilities.

Many developers assume that keeping their repositories private is enough, but that’s not the case. If a secret is present in your code, it can still be leaked through:

  • Accidental pushes to public repositories.
  • Code reviews and log files.
  • Reverse engineering of compiled binaries.

Why Detect Secrets During Build Time?

Once a secret is committed to a repository or embedded in a compiled application, itโ€™s already at risk. Thatโ€™s why detecting secrets earlyโ€”during the build processโ€”is essential.

By implementing automatic secret detection in your CI/CD pipeline, you can:

  • Prevent secrets from being pushed to version control.
  • Ensure that compiled binaries do not contain sensitive information.
  • Reduce the risk of exposing credentials in production environments.

Security best practices recommend integrating automated tools into your build process to identify and eliminate secrets before they become a problem.

Tools for Secret Detection in .NET

image 26

Several tools can help detect secrets automatically:

  • Online Secrets Sprawl โ€“ Scans repositories to detect exposed secrets, even in private repos.
  • ByteHide Secrets โ€“ Integrates into your project to detect secrets every time the code is compiled.
  • GitHub Secret Scanning โ€“ Detects exposed credentials in repositories and alerts developers.
  • TruffleHog โ€“ Uses pattern matching and entropy analysis to detect secrets in codebases.

The best way to prevent hardcoded secrets is to automate their detection while coding. In the next section, Iโ€™ll show you how to integrate this directly into your .NET project so that secrets are flagged every time you compile.

Detecting Secrets in .NET automatically with MSBuild

Alright, we’ve talked about why detecting secrets is crucial, but now it’s time to actually implement it in our .NET project. The goal here is simple: every time we compile our application, secrets should be detected automatically.

Weโ€™re going to set up ByteHide Secrets so that it integrates directly into our build process, alerts us when secrets are found, and even allows us to define actions when a secret is detected.

Letโ€™s break it down step by step.

0. Setup your project

Yes, 0. we are developers.

You must do it in your real project, but, for this article i’ll setup a sample project with a harcoded secret ๐Ÿ˜€

image 11

1. Install Secrets Scanning in Your Project

The first thing we need to do is install the ByteHide Secrets Integration package in our .NET project. Open a terminal in your projectโ€™s root directory and run:

dotnet add package Bytehide.Secrets.Integration

This will add the package and configure it to work with MSBuild.

2. Get Your Free Project Token

To link our project with ByteHide and track detected secrets in a central panel, we need an API token.

Follow these steps:

  • Go to ByteHide and create a free account.
  • In the dashboard, create a new .NET project and select Secrets.
image 15
  • Copy the Project Token provided after creating the project.
image 16

This token allows ByteHide to monitor detected secrets, send alerts, and apply custom actions.

3. Create the Configuration File

Now that we have our project token, we need to create a configuration file inside our project.

Create a new file in the root of your project and name it:

secrets-config.json

Open the file and add the following content:

{
  "Name": "My Configuration",
  "ProjectToken": "YOUR_PROJECT_TOKEN",
  "Environment": "develop"
}

Replace YOUR_PROJECT_TOKEN with the token you copied earlier.

4. Customize the Detection Behavior

ByteHide Secrets allows us to customize how secrets are detected and handled. Here are some useful settings you can modify in secrets-config.json:

  • RunConfiguration: Defines when secret detection should run. Default is * (runs in all cases).
  • Enabled: Set to false if you want to temporarily disable detection.
  • DisplayCode: If true, stores an extract of the detected secret in the ByteHide panel.
  • ThrowOnError: If true, stops compilation when an error occurs.
  • Actions: Configure what happens when a secret is found (e.g., email alerts, webhook notifications).

Example configuration:

{
  "Name": "Production Build",
  "ProjectToken": "YOUR_PROJECT_TOKEN",
  "Environment": "production",
  "RunConfiguration": "*",
  "Enabled": true,
  "DisplayCode": true,
  "ThrowOnError": false
}

5. Run the Build Process (and scan secrets)

With everything set up, let’s compile our project:

Click on compile:

image 7

or:

dotnet build

If ByteHide Secrets detects any hardcoded credentials, it will:

  • Stop the build process (if ThrowOnError is enabled).
  • Log the detected secrets.
  • Send alerts (if email or webhook actions are configured).
image 8

And it will appear in the security panel:

image 10

Now that secret detection is automated, we can focus on securing them properly. ByteHide Secrets also offers an integrated panel where you can:

  • View detected secrets.
  • Manage secret replacements.
  • Configure advanced protection settings.

In the next section, we’ll go a step further and see how to automatically extract and store secrets securely, rather than just detecting them.

Extracting and Storing Secrets Securely

Detecting secrets in your code is a great first step, but detection alone isnโ€™t enough. Once a secret is identified, we need to extract it and store it securelyโ€”otherwise, it remains a security risk.

Instead of leaving secrets hardcoded in our applications, we can use ByteHide Secrets to automatically extract and manage them, ensuring they never get exposed in the first place.

Let’s go through the process step by step.

1. Why Extract Secrets?

Secrets embedded in source code or compiled binaries can be accessed through:

  • Version control (e.g., Git commits that store API keys by mistake).
  • Decompilation (attackers can reverse-engineer your application to extract secrets).
  • Logs and debugging tools that might print sensitive values.

By extracting secrets, we keep them out of our codebase and manage them in a secure environment.

2. Enabling Automatic Secret Extraction

Once ByteHide Secrets is installed and configured in our project, we can enable automatic secret extraction.

To do this, add the following option to your secrets-config.json file:

{
  "Name": "Production Secrets",
  "ProjectToken": "YOUR_PROJECT_TOKEN",
  "Environment": "production",
  "export": {
    "enabled": true,
    "encrypt": true,
    "prefix": "secret_"
  }
}

Hereโ€™s what each setting does:

  • enabled: If set to true, secrets will be extracted and stored in ByteHide’s cloud.
  • encrypt: If set to true, the ID of extracted secrets will be encrypted in the binary (This is a extra-security feature to combat reversing analyzers) .
  • prefix: Defines a prefix for replaced secrets, making it easier to track them.

3. Running the Extraction Process

With extraction enabled, all we need to do is build our project:

dotnet build

ByteHide Secrets will scan our application, detect sensitive data, and replace it with a reference.

So, in the code, the hardcode secret will be replaced with the secure vault reference of this secret,

Before:

image 13

After:

image 12

Cool! Now the secret is not anymore in the code/binary and it’s sync in our dashboard, so:

4. Where Are the Extracted Secrets Stored?

Extracted secrets are stored in the ByteHide Secrets Manager, where they can be accessed securely.

image 14

From the panel, you can:

  • View and manage detected secrets.
  • Assign environment-specific values (e.g., different API keys for dev, staging, and production).
  • Apply role-based access control (RBAC) to manage who can see or use secrets.

Managing Secrets During Development

Ideally, secrets should never be hardcoded in the first place. If we set up proper secret management from the start, we wonโ€™t need to rely on automatic extraction. However, whether we extract them automatically or manage them manually, the security level remains the same.

The key difference is that if secrets are not handled correctly in the code, they can still end up in version control (e.g., Git) before being detected. Letโ€™s look at two ways to manage secrets correctly during development.

1. Marking Secrets Manually

Sometimes, secrets may not be detected automaticallyโ€”this could be because they are very simple (e.g., a password for encrypting a .zip file) or follow an unconventional pattern. In these cases, we can explicitly mark them for protection.

First, install the ByteHide ToolBox package:

dotnet add package Bytehide.ToolBox.Secrets

Then, use the ThisIsASecret method to manually mark the secret:

using System;
using Bytehide.ToolBox.Secrets;

namespace Hollow
{
    internal class Program
    {
        private static void Main()
        {
            var password = SecretsMarker.ThisIsASecret("drowssap", "my_db_password");
            var database = new DB.Database("Hollow", password);
            database.CreateDatabase();

            Console.ReadKey();
        }
    }
}

Alternatively, we can use the IsASecret extension method:

var password = "drowssap".IsASecret("my_db_password");

If we prefer, we can also use an attribute to mark a class-level secret:

using System;
using Bytehide.ToolBox.Secrets;

namespace Hollow
{
    internal class Program
    {
        [ThisIsASecret("my_db_password")]
        private static readonly string _password = "drowssap";

        public static void Main()
        {
            var database = new DB.Database("Hollow", _password);
            database.CreateDatabase();

            Console.ReadKey();
        }
    }
}

2. Managing Secrets Securely with ByteHide Secrets SDK

The best way to handle secrets is to store them securely from the beginning. Instead of writing secrets in the code, we can:

image 17
  • Click on “Create secret”
image 18
  • Add the name, the value and select your environment. Click on “Create”
image 19
  • Now, you will see the secret under “keys” tab.

Cool, go now to our visual studio project,

  • Install the ByteHide Secrets SDK in our application:
dotnet add package Bytehide.ToolBox.Secrets

Configuring the Secrets Manager Securely

To securely interact with ByteHide Secrets from the SDK, we need to provide our API Key. Since this key grants access to our secrets, it should never be hardcoded. Instead, we have three options:

  • โœ… Secure (Recommended): Store the API Key in an environment variable.
  • โš ๏ธ Acceptable: Store the API Key in app.config.
  • โŒ Insecure (Not Recommended): Hardcode the API Key in the source code.
Option 1: Using Environment Variables (Recommended)

We can set the API Key as an environment variable in our operating system:

export BYTEHIDE_SECRETS_TOKEN=e34762f8-8ad6-0000-0000-000000000000

Then, in our application, initialize the secrets manager:

namespace Sample;

internal class Program
{
    internal static void Main()
    {
        // Initialize the secrets manager (API Key is automatically retrieved from the environment variable)
        Bytehide.ToolBox.Secrets.ManagerSecrets.Initialize();

        var secrets = Bytehide.ToolBox.Products.Secrets;

        // Get a secret from ByteHide Secrets Manager
        var value = secrets.Get("mongo-db-password");

        Console.WriteLine($"My secret is: {value}");
        Console.ReadLine();
    }
}
Option 2: Using app.config

If using environment variables is not an option, we can store the API Key in app.config:

<configuration>
    <appSettings>
        <add key="ByteHide.Secrets.Token" value="e34762f8-8ad6-0000-0000..."/>
    </appSettings>
</configuration>

Then, initialize the secrets manager using:

Bytehide.ToolBox.Secrets.ManagerSecrets.Initialize(true);
Option 3: Hardcoding the API Key (Not Recommended)

For testing purposes only, we can directly set the API Key in code. This method is highly discouraged for production environments:

Bytehide.ToolBox.Secrets.ManagerSecrets.UnsecureInitialize("development", "e34762f8-8ad6-0000-0000...");

Getting the secrets in our code

Once our SDK is initialized, the recommendation is to do it in the methods that are executed first in our application.

Now, we can get the secrets wherever we want in a secure way, such as before connecting to a database:

var secrets = Bytehide.ToolBox.Products.Secrets;

// Get a secret from ByteHide Secrets Manager
var value = secrets.Get("mongo-db-password");

mongoDB.connect("127.0.0.0", value);

And there we have it ๐ŸŽ‰! Secrets that are updated from the panel will be synchronized in our code.

In addition, it performs several security checks to avoid network sniffing, reverse engineering and credential theft.

Now let’s see how we can add new secrets from the code in our cloud manager.

3. Creating Secrets Programmatically

Instead of manually creating secrets in the panel, we can also create them dynamically from our application:

namespace Sample;

internal class Program
{
    internal static void Main()
    {
        Bytehide.ToolBox.Secrets.ManagerSecrets.Initialize();

        var secrets = Bytehide.ToolBox.Products.Secrets;

        // Create a new secret
        secrets.Set("new-secret", "secure-value");

        Console.WriteLine("Secret successfully created.");
        Console.ReadLine();
    }
}

Now let’s explore how to securely share secrets across teams without exposing them in plaintext.

Securely Sharing Secrets Across Teams

When working in a development team, sharing secrets like API keys, database credentials, or encryption keys can become a challenge. Sending secrets over Slack, email, or even embedding them in a shared repository poses a serious security risk.

Instead of handling secrets manually, we can use ByteHide Secrets Manager to securely share and manage access to secrets across teams.

Letโ€™s explore two ways to do this.

1. Managing Teams in the Secrets Manager

The most secure way to share secrets with your team is to manage access directly within the Secrets Manager. This allows for:

  • Role-based access control (RBAC) to define who can view or modify secrets.
  • Environment-specific secrets, so teams can use different credentials for development, staging, and production.
  • A centralized audit log to track who accessed or modified a secret.

How to Set Up Team Management

Once set up, team members can retrieve secrets directly from the ByteHide panel or through the SDK without needing to manually exchange sensitive information.

  • Navigate to the Teams section and create a new team:
image 20
  • Add team members by entering their email addresses or current organization members.
  • Also Assign roles and permissions:
    • Owner: Full access to secrets and team management, can remove secrets, vaults and projects.
    • Manager: Can read/add secrets and modify them.
    • Member: Can only view specific secrets.
image 22
  • Now, with our new team created:
image 23
  • Create a new project or open an existing one (update) and add the team to the “Teams” of the project.
image 24

We now have under control who can, who can’t, and the permissions on secrets within our development team.

What if it’s a simple secret that we don’t want to keep in the manager? Or share it with someone external? Let’s get to it.


2. Securely Sharing Secrets Without Adding Users

Sometimes, you need to share a secret with someone who isnโ€™t part of your team, like a freelancer or an external service. Instead of sending secrets via insecure channels, we can use ByteHide Secure Sharing.

image 25

How to Share a Secret Securely

  1. Go to ByteHide Secure Sharing.
  2. Paste the secret you want to share.
  3. Set an expiration time (e.g., 1 minutes, 12 hour, 24 hours).
  4. Choose the number of times the secret can be viewed before it is deleted.
  5. Generate a secure shareable link.
  6. Send the link to the recipient.

Once the recipient views the secret, it will be automatically deleted, ensuring it cannot be accessed again.

What’s Next?

By now, weโ€™ve covered everything you need to detect, extract, and manage secrets securely in your .NET projects. But securing secrets isnโ€™t just a one-time task, itโ€™s an ongoing process.

Preventing secrets from leaking into your codebase, automating their detection during builds, and managing them properly across different environments and teams are essential steps to keeping your applications secure.

Now itโ€™s your turn! Start implementing these strategies in your projects and take control of your secrets before they become a security risk.

Frequently Asked Questions (FAQ)

What are hardcoded secrets in .NET, and why are they a security risk?

Hardcoded secrets are sensitive data, such as API keys, database credentials, and encryption keys, that are directly embedded in a project’s source code. These secrets pose a security risk because they can be accidentally leaked through version control (e.g., GitHub repositories) or extracted using reverse engineering techniques.

How can I find hardcoded secrets in my .NET application?

To detect hardcoded secrets in .NET projects, you can use automated tools such as TruffleHog, Detect Secrets, or integrate secret detection into your CI/CD pipeline with ByteHide Secrets. These tools scan source code and configuration files to identify exposed secrets.

How do I prevent secrets from being pushed to Git repositories?

To avoid committing secrets to Git, you can:

  • Add sensitive files to .gitignore.
  • Use Git Secrets to block commits containing sensitive information.
  • Implement pre-commit hooks to scan for secrets before pushing code.
  • Store secrets in environment variables or a secrets manager instead of hardcoding them.

What is the best way to store API keys securely in a .NET application?

The best practices for storing API keys securely in .NET include:

How do I use .NET user secrets for local development?

.NET provides the User Secrets feature to store sensitive data outside of source control. To use it:

  1. Run dotnet user-secrets init in your project root.
  2. Add secrets using dotnet user-secrets set "ApiKey" "your-secret-key".
  3. Retrieve secrets in code using Configuration["ApiKey"].

How do I encrypt and store sensitive data in .NET?

You can encrypt sensitive data in .NET using:

What is secret sprawl, and how can I prevent it?

Secret sprawl occurs when sensitive credentials are scattered across multiple locations, making them difficult to track and secure. To prevent secret sprawl:

  • Use a centralized secrets manager.
  • Implement access controls and audit logs.
  • Scan repositories regularly for leaked secrets.

How can I detect exposed secrets in my Git repository?

You can scan Git repositories for exposed secrets using tools like:

How do I securely share secrets with my development team?

To securely share secrets with a team, avoid sharing credentials via chat apps or emails. Instead, use:

  • A role-based access control system in a secrets manager.
  • ByteHide Secure Sharing for expiring, one-time secret links.

What happens if a secret is leaked in my application?

If a secret is leaked, follow these steps immediately:

  1. Revoke the exposed credential (e.g., rotate API keys or change passwords).
  2. Remove the secret from source control using git filter-branch or BFG Repo Cleaner.
  3. Implement automated secret detection to prevent future leaks.

What Do You Think?

Weโ€™ve covered everything from detecting hardcoded secrets to securely storing and sharing them in .NET applications. Implementing these best practices can significantly improve your applicationโ€™s security and prevent accidental leaks.

Now, Iโ€™d love to hear from you! Have you faced issues with secrets management in your projects? Do you already use a secrets manager, or are you still handling credentials manually?

Drop a comment below and let me know your thoughts! If you have any questions, Iโ€™ll be happy to help.

Fill out my online form.

Leave a Reply