How to Perform an Effective Security Code Review for .NET
A security code review examines how an application behaves under misuse, not just whether its features work as designed. For a .NET system, that means tracing data from HTTP requests, message queues and file uploads through controllers, services, data access layers and external integrations. The review should reveal weaknesses early enough for developers to fix them before release, rather than treating penetration testing as the first serious security check. Learn more about Using Azure Monitor And Application Insights For Performance Analysis.html.
Australian delivery teams face a broad range of operating conditions. A Melbourne SaaS provider may host customer data in Azure, while a Sydney organisation may integrate with government services, banks or healthcare platforms. The Privacy Act 1988, Australian Privacy Principles and Notifiable Data Breaches scheme also make secure handling of personal information a business responsibility, not simply a technical preference. Learn more about Security Testing In The Sdlc Integrating Owasp Zap Into Your Pipeline.html.
Set A Clear Review Scope
Begin by defining the application, version, repositories and deployment environments included in the review. Record the .NET version, web framework, identity provider, databases, cloud services, background workers and third-party packages. A review of an ASP.NET Core API has different priorities from one of an older ASP.NET MVC application with Windows authentication and server-rendered views. Learn more about How To Conduct A Software Testing Maturity Assessment.html.
Identify the most valuable assets and the consequences of compromise. These may include customer records, payment details, access tokens, clinical information, source code or administrative functions. Map the roles that can reach each asset, including support staff, service accounts, external partners and unauthenticated visitors. This provides a risk-based focus instead of producing a long list of equally weighted style observations.
The scope should include source code, configuration, infrastructure definitions and relevant build scripts. Secrets can leak through appsettings files, pipeline variables, Docker images and deployment templates even when the application code appears sound. Agree on how findings will be classified, usually by impact and exploitability, and define who owns remediation for each component.
Map Trust Boundaries And Data Flows
Create a simple data-flow model before examining individual methods. Show browsers, mobile clients, APIs, queues, databases, caches, identity services and external providers. Mark where the system crosses a trust boundary, such as a public API calling an internal service or a worker consuming a message generated by a customer-controlled request.
For each flow, ask whether the application validates the data, authenticates the caller, authorises the requested action and protects the information in transit and at rest. A value may be safe at the controller boundary but become dangerous when reused in a SQL query, file path, HTML response or shell command. Follow the value through the complete execution path rather than approving a method in isolation.
Pay close attention to multi-tenant systems common in Australia’s growing SaaS market. Tenant identifiers should come from a trusted server-side context and be enforced in every query and storage operation. A hidden form field, route value or JWT claim must not be treated as proof that a user can access another organisation’s records.
Examine Identity And Input Handling
Review authentication flows for secure password storage, sensible session expiry, protection against credential stuffing and safe recovery processes. In ASP.NET Core, inspect cookie settings such as Secure, HttpOnly and SameSite, along with antiforgery protection for state-changing browser requests. For token-based APIs, verify issuer, audience, expiry, signature validation and secure storage on client devices.
Authorisation deserves a separate pass. Confirm that policies, roles and resource-based checks are applied at the point where an action occurs, rather than relying on a menu hiding a button. Test horizontal access control by changing record identifiers between users with the same role, and test vertical escalation by invoking administrative endpoints directly.
Treat every request value as untrusted, including JSON properties, headers, uploaded filenames, query strings and claims from external identity systems. Use allowlists and strongly typed models where practical, enforce length and format limits, and reject unexpected fields when the endpoint handles sensitive operations. Parameterised queries help prevent injection, but reviewers should also examine dynamic sorting, filtering and raw SQL paths that may bypass normal safeguards.
Review .NET-Specific Attack Paths
Inspect Entity Framework Core queries for unsafe string construction, over-posting and accidental exposure of navigation properties. Binding an entire entity from a request can allow a caller to change fields such as IsAdmin, AccountStatus or OwnerId. Dedicated request models and explicit property mapping make the permitted update surface clear.
Review Razor views and API responses for cross-site scripting. Razor’s default HTML encoding is helpful, yet developers can bypass it with Html.Raw, custom formatters or unsafe JavaScript interpolation. JSON placed into scripts, URLs or HTML attributes needs context-appropriate encoding. Also check redirect targets, returnUrl parameters and CORS rules, since permissive settings can turn a harmless-looking endpoint into a useful step in an attack.
File handling requires careful scrutiny. Verify content type and file signature rather than trusting the extension, limit size, generate server-side names and store uploads outside executable web paths. Archives need protection against path traversal and decompression bombs. For systems processing PDFs, images or office documents, isolate parsers where possible and keep them patched.
Cryptography should use established .NET APIs and modern algorithms rather than custom routines. Look for hard-coded keys, predictable tokens, reversible encryption used as password storage and logs containing bearer credentials. Key Vault or an equivalent managed secret store is preferable to committing secrets into a repository or distributing the same key across development, test and production.
Check Configuration And Dependencies
Configuration review often exposes issues that ordinary functional testing misses. Check that production error pages do not reveal stack traces, connection strings or framework details. Confirm that debug settings are disabled, management endpoints are restricted, transport security is enforced and security headers are appropriate for the application. Review Kestrel, IIS, reverse proxy and container settings together because a secure application can be weakened by its hosting layer.
Audit NuGet packages and transitive dependencies for known vulnerabilities, unsupported versions and unnecessary components. A vulnerable package may be reachable only through a rarely used feature, but that assumption should be demonstrated rather than accepted. Pin versions where appropriate, enable automated dependency alerts and define a rapid process for evaluating critical advisories.
Logging should support investigation without becoming a privacy liability. Record authentication failures, privilege changes, suspicious input and important data access with correlation identifiers, while excluding passwords, full payment details, access tokens and unnecessary personal information. Australian organisations should align retention and access practices with their privacy obligations, especially where logs are copied to overseas services.
For applications subject to the Australian Privacy Principles or the Notifiable Data Breaches scheme, connect technical findings to the organisation’s incident response process. A lost token, exposed database backup or compromised administrator account should have a documented path for containment, assessment and notification. This makes the review relevant to operational risk rather than limiting it to code defects.
Validate Findings With Testing
Static analysis can identify insecure APIs, injection patterns, weak cryptography and exposed secrets, but it cannot understand every business rule. Combine automated scanning with targeted manual review and tests that exercise abuse cases. Useful scenarios include accessing another tenant’s invoice, replaying a password-reset token, changing a user’s role through mass assignment and uploading a file with a misleading extension.
Dynamic testing should run against a controlled environment with representative roles and data. Use an intercepting proxy to inspect requests, alter identifiers and test unexpected sequences. Integrating OWASP ZAP pipeline checks into CI can provide repeatable baseline scanning, while manual assessment remains necessary for authorisation and workflow flaws.
Performance and security can interact in surprising ways. Expensive validation, uncontrolled regular expressions, oversized requests and repeated cryptographic operations can create denial-of-service conditions. Application telemetry helps distinguish a genuine attack from a busy release or failing dependency; teams can pair the review with performance telemetry from Azure Monitor and Application Insights.
Treat tool output as evidence to triage, not as an automatic verdict. Confirm whether a finding is reachable, identify the affected asset and reproduce it safely. False positives consume developer attention, while vague findings such as “possible injection” do little to guide remediation.
Turn Findings Into Continuous Control
A useful security review produces a finding that a developer can act on. Include the location, weakness, realistic attack path, affected versions, business impact, severity and a concise remediation pattern. For example, “enforce tenant ownership in the service query” is more useful than “fix access control.” Add a regression test where possible so the issue does not return during refactoring.
Prioritise vulnerabilities according to exposure and consequence. An unauthenticated command injection issue should outrank a missing header on an internal tool, while a tenant isolation flaw deserves urgent attention even if exploitation requires a normal account. Assign owners and due dates, then verify the fix through code review and retesting rather than closing the ticket when a branch is merged.
Place security checks at suitable stages of the delivery lifecycle. Secrets scanning, dependency analysis and SAST can run on pull requests; API abuse tests and dynamic scanning can run in integration environments; deeper manual reviews can support major releases. A testing maturity assessment can help identify whether the organisation has repeatable security practices or relies on individual specialists.
Review the process after incidents, major architecture changes and framework upgrades. A move from on-premises hosting to Azure, a new single sign-on provider or an added mobile client can alter trust boundaries and create fresh review priorities. Security code review works best as a normal part of Agile and DevOps delivery, with fast feedback for developers and clear evidence for risk owners.
A disciplined review gives .NET teams a practical way to reduce exploitable defects before they reach Australian customers, partners and regulators. Start with one critical service, map its data flows, inspect its identity and input controls, automate repeatable checks, and track each finding through verified remediation. Contact nFocus Software Testing to support security testing, automation and continuous quality practices across your .NET delivery environment.