CISSP-117 · Lesson 9 of 12 · 25 min
Code review and application security testing
The fourth Domain 8 objective asks you to assess the effectiveness of software security. Effectiveness is assessed in two ways: by examining the software itself through review and testing, and by examining the process that produces it through audits, metrics and maturity assessments. This lesson covers the first. It explains the main review and testing techniques, where each fits in the life cycle, what each finds and misses, and how a manager turns a stream of tool findings into risk reduction rather than noise.
CISSP-115 Lesson 8 introduced security testing in the software life cycle as part of an organization-wide assessment and testing program, and its Lessons 3 to 5 covered vulnerability scanning, scoring with CVSS, EPSS and KEV, and penetration testing methodology and rules of engagement. This lesson does not repeat those topics. It looks at the same techniques from inside the development organization: how they are built into daily work, how they are tuned and how their results are used.
Peer code review
Code review, in which one or more developers examine a change before it is merged, is the oldest and still one of the most effective quality and security practices. Reviews catch logic errors, missing authorization checks, misuse of security functions and violations of the coding standard that tools miss, and they spread knowledge across the team. They also provide separation of duties: a malicious or careless change needs a second person to approve it. Lesson 4 described how branch protection enforces review.
Reviews are only as good as the reviewers' attention and knowledge. Large changes receive superficial reviews, so teams should keep pull requests small. Checklists focused on the organization's common weaknesses help reviewers look for the right things. Sensitive code, such as authentication, authorization, payment logic and cryptography, should be assigned to designated code owners with security expertise. Formal inspections, a more structured technique with defined roles and meetings, are used for safety-critical and high-assurance software. Reviews of infrastructure-as-code and pipeline definitions matter as much as reviews of application code, because a single changed line in a cloud configuration can expose a database.
Static application security testing
Static application security testing (SAST) analyses source code, bytecode or binaries without running them, looking for patterns that indicate weaknesses, such as data flowing from an untrusted input to a database query without parameterization. Because it needs no running application, SAST can run in the developer's IDE and on every pull request, giving feedback within minutes. It covers all code paths, including rarely executed ones. Its weaknesses are false positives, which waste time and erode trust, and false negatives for weaknesses that depend on configuration, runtime behaviour or business rules. SAST results improve markedly when rules are tuned to the organization's frameworks and when developers can mark findings as false positives with a recorded justification that the security team can review.
Dynamic, interactive and runtime testing
Dynamic application security testing (DAST) examines a running application from the outside, sending requests and analysing responses, much as an external user would. It finds problems that only appear at runtime, such as misconfigured servers, missing security headers, weak session handling and some injection flaws, and its findings are usually real. It cannot see inside the code, may miss pages it cannot reach, and needs a working environment, so it runs later, typically against staging and sometimes against production with care.
Interactive application security testing (IAST) places sensors inside the running application, usually through an agent in the runtime, and observes data flows while functional tests or users exercise the application. It combines some of the code visibility of SAST with the runtime accuracy of DAST and produces fewer false positives, but it depends on test coverage and supports only certain languages. Runtime application self-protection (RASP) uses similar instrumentation in production to detect and block attacks as they happen. RASP is a protective control rather than a testing technique, and like a web application firewall it should be treated as a compensating layer, not a substitute for fixing defects.
Software composition analysis
Modern applications are mostly made of third-party components. Software composition analysis (SCA) identifies the open source and commercial components in an application, including transitive dependencies that the developers never chose directly, and reports known vulnerabilities and licence obligations for each. Good SCA tools also judge reachability, that is, whether the application actually calls the vulnerable code, which helps teams prioritize. SCA is the foundation of the software bill of materials discussed in Lesson 10.
Fuzzing
Fuzz testing feeds a program large volumes of automatically generated, malformed or unexpected input to find crashes, hangs and assertion failures that indicate defects such as memory safety errors. Coverage-guided fuzzers observe which code paths each input exercises and evolve inputs to reach new paths, which makes them remarkably effective at finding deep bugs in parsers, file format handlers and network protocol code. Fuzzing belongs in the developer's own test suite and in continuous integration for components that handle untrusted input; Google's OSS-Fuzz service has found thousands of vulnerabilities in widely used open source projects this way. For a manager, the governance points are that fuzzing is aimed at the organization's own code in its own test environments, and that crashes it finds are treated as potential security defects until shown otherwise.
Security unit tests, misuse tests and test coverage
Functional tests check that software does what it should. Security tests also check that it refuses what it should refuse. Every security requirement from Lesson 1 should have at least one test: a refund larger than the payment is rejected, a viewer cannot create refunds, a request for another merchant's object returns not found, a session expires after the idle timeout. These negative tests run in the pipeline with every change, which turns the security requirements into permanent regression checks. Test coverage metrics show how much of the code the tests exercise; high coverage does not prove security, but very low coverage of security-sensitive code is a warning sign worth acting on.
| Technique | When it runs | Strengths | Limitations |
|---|---|---|---|
| Peer review | Before merge | Finds logic and design issues; separation of duties | Depends on reviewer time and skill |
| SAST | IDE, pull request, build | Early, covers all code paths | False positives; misses runtime and logic issues |
| SCA | Build, continuously | Finds known vulnerable and unlicensed components | Only known issues; noise without reachability |
| DAST | Test, staging, production | Realistic, few false positives, finds configuration issues | Late; limited code visibility and coverage |
| IAST | During functional testing | Accurate with code context | Needs agents and good test coverage |
| Fuzzing | Build and test | Finds crashes and memory errors in input handlers | Needs harnesses; best for parsers and protocols |
| Penetration test | Before major releases or periodically | Human creativity; finds chained and logic flaws | Point in time; costly; scope-limited |
Turning findings into risk reduction
Running tools is easy; using their output well is hard. A new SAST deployment on a large code base can report thousands of findings, most of them low risk or false positives. If every finding blocks the pipeline, teams revolt; if findings are simply dumped into a backlog, nothing improves. The usual approach is to establish a baseline of existing findings, block only on new high-confidence, high-severity findings in changed code, triage the backlog by risk, and measure the precision of each rule so that noisy rules are tuned or disabled.
import random
random.seed(11)
# Triage results for SAST rules over one quarter (synthetic data)
rules = { # rule: (findings raised, probability a finding is a true positive)
'sql-string-concat': (48, 0.80),
'xss-unescaped-output': (35, 0.55),
'weak-hash-function': (60, 0.25),
'hardcoded-credential': (22, 0.70),
'generic-taint-flow': (310, 0.06),
}
total_raised = total_true = 0
print(f"{'rule':22s} {'raised':>6s} {'true':>5s} {'precision':>9s} action")
for rule, (n, p) in rules.items():
tp = sum(random.random() < p for _ in range(n))
total_raised += n; total_true += tp
prec = tp / n
action = 'block on new' if prec >= 0.5 else ('report only' if prec >= 0.2 else 'tune or disable')
print(f'{rule:22s} {n:6d} {tp:5d} {prec:9.0%} {action}')
print(f'Overall precision {total_true / total_raised:.0%}; '
f'{rules["generic-taint-flow"][0] / total_raised:.0%} of findings come from one noisy rule')rule raised true precision action sql-string-concat 48 39 81% block on new xss-unescaped-output 35 21 60% block on new weak-hash-function 60 21 35% report only hardcoded-credential 22 15 68% block on new generic-taint-flow 310 15 5% tune or disable Overall precision 23%; 65% of findings come from one noisy rule
In this synthetic quarter, one generic rule produced most of the findings while finding very little. Disabling it outright might lose its few real detections, so the better course is to tune it for Ridgeline's frameworks, for example by recognizing the approved query library as safe. Precision-based policies like this keep developer trust, which is the scarcest resource in an application security program.
Findings must flow into the same defect tracking system that teams use for other work, with severity, owner and due date. Remediation deadlines are usually tied to severity and exposure, such as 7 days for a critical issue in an internet-facing service and 90 days for a medium issue in an internal one. Findings that cannot be fixed in time go through the risk acceptance process described in Lesson 1. Lesson 12 covers the metrics a program uses to report on all of this.
Independent testing, bug bounties and disclosure programs
Internal testing is complemented by independent perspectives. Penetration tests by qualified internal or external testers, run under written authorization and rules of engagement as CISSP-115 explains, are appropriate before major releases, after significant architectural changes and periodically for high-risk applications. A vulnerability disclosure program (VDP) publishes a policy and a channel through which anyone can report security issues in good faith, with a commitment to respond and not to pursue legal action against good-faith researchers who follow the rules. A bug bounty program adds payment for valid findings, usually run through a platform that manages researchers and triage. Both require a mature internal process to receive, verify and fix reports quickly; launching a bounty before that process exists invites frustration on all sides. Government guidance in both Canada and the United States encourages organizations to publish disclosure policies, and the EU Cyber Resilience Act will require manufacturers of products sold in the EU to have coordinated vulnerability disclosure policies.
Worked problem
Introducing SAST without stalling delivery
Ridgeline turns on a SAST tool across its main repository and it reports 2,400 findings. Developers threaten to switch it off. The CTO asks the application security lead for a plan.
Show solution
- Baseline the existing findings so they do not block builds, and block only on new critical and high findings from rules with measured precision above 50 %.
- Triage the baseline by exposure and severity: findings in internet-facing payment code first, with a target of clearing the top 100 within a quarter.
- Tune noisy rules for Ridgeline's frameworks and record false positive decisions with justifications that the security team samples monthly.
- Report weekly: new findings introduced, findings fixed, baseline remaining and rule precision, so progress is visible and the tool earns trust.
Answer: Baseline, block narrowly on new high-confidence findings, triage by risk, tune continuously and report progress.
Common mistakes
MistakeApproving large pull requests after a quick glance.
InsteadKeep changes small, use checklists and assign sensitive code to qualified code owners.
MistakeBlocking every build on every SAST finding.
InsteadBaseline existing findings and block only on new, high-confidence, high-severity ones.
MistakeTreating RASP or a web application firewall as a fix.
InsteadUse them as compensating layers while defects are corrected in code.
MistakeScanning only direct dependencies.
InsteadUse SCA that covers transitive dependencies and assesses reachability.
MistakeTesting only that features work.
InsteadWrite negative security tests for every security requirement and run them on every change.
MistakeLaunching a bug bounty without a process to handle reports.
InsteadBuild intake, triage and remediation first, then publish a disclosure policy and consider a bounty.
Summary and key terms
- Effectiveness is assessed by examining the software (review and testing) and the process (metrics, audits, maturity).
- Peer review finds logic and design issues and enforces separation of duties; keep changes small and use code owners.
- SAST analyses code early and broadly but produces false positives; DAST tests running applications; IAST observes from inside during tests.
- SCA identifies third-party components, known vulnerabilities and licences, ideally with reachability analysis.
- Fuzzing finds crashes and memory errors in input-handling code and belongs in continuous integration.
- Security tests turn requirements into regression checks; RASP and WAFs are compensating controls.
- Findings need baselining, precision-based tuning, severity-based deadlines and integration with normal defect tracking.
- SAST
- Static application security testing, analysis of code without running it.
- DAST
- Dynamic application security testing, testing a running application from outside.
- IAST
- Interactive application security testing, instrumentation inside a running application during tests.
- RASP
- Runtime application self-protection, in-application detection and blocking of attacks in production.
- Software composition analysis
- Identifying third-party components and their known vulnerabilities and licences.
- Fuzz testing
- Feeding large volumes of generated, unexpected input to find crashes and defects.
- Vulnerability disclosure program
- A published policy and channel for good-faith reporting of security issues.
- Code owner
- A designated reviewer who must approve changes to specific sensitive code.
Practice problems
Work each problem on paper first, then reveal the answer to check.
Name two ways to assess software security effectiveness.
Show answer
Examining the software through review and testing, and the process through metrics, audits and maturity assessments.
Why should pull requests be small?
Show answer
Large changes get superficial reviews.
What is the main weakness of SAST?
Show answer
False positives, plus misses for runtime and business logic issues.
Why are DAST findings usually real?
Show answer
They are observed in the behaviour of the running application.
How does IAST differ from DAST?
Show answer
It instruments the application from inside, giving code context during tests.
What is reachability in SCA?
Show answer
Whether the application actually calls the vulnerable code in a component.
What kind of code benefits most from fuzzing?
Show answer
Code that parses untrusted input, such as file formats and protocols.
What is a negative security test?
Show answer
A test that checks the software refuses something it should refuse.
How should a team handle thousands of existing SAST findings?
Show answer
Baseline them, block only new high-confidence findings, triage by risk and tune rules.
What distinguishes a bug bounty from a VDP?
Show answer
A bounty pays rewards for valid findings; a VDP provides a reporting channel and policy.
Lesson quiz · 5 questions
Score 60% or more to complete this lesson.
Create a free account to save your progress, take quizzes and earn a certificate.