10. Secure Java Engineering and GovernanceIntroduction and ContextSecurity in Java engineering is not a feature added at the end of development. It is a property of the entire software life cycle: requirements, architecture, coding, testing, deployment, operation, maintenance, and retirement. A Java application may use a secure virtual machine and still be vulnerable because of weak authentication, excessive privileges, unsafe deserialization, exposed secrets, flawed input handling, or a compromised dependency. For postgraduate software engineers, secure development therefore requires more than knowledge of APIs. It requires the ability to evaluate threats, select controls, interpret governance obligations, and balance security with usability, performance, maintainability, privacy, and business objectives. This chapter presents secure Java engineering as both a technical discipline and an organizational responsibility. The discussion applies to Java web services, enterprise systems, mobile back ends, cloud-native applications, batch systems, and libraries. It also connects implementation decisions with software supply-chain governance, licensing, auditability, privacy, and professional ethics. Learning ObjectivesAfter studying this chapter, the student should be able to: 1. Distinguish authentication, authorization, accounting, and auditability in Java systems. 2. Apply secure principles to passwords, tokens, cryptography, secrets, and input validation. 3. Explain the risks associated with deserialization and vulnerable dependencies. 4. Design practical controls for privacy, software supply-chain security, and licensing. 5. Use secure coding standards, SBOMs, testing, logging, and governance processes. 6. Evaluate an application security scenario and recommend proportionate controls. 7. Recognize ethical responsibilities associated with data protection, disclosure, and security decisions. Security as an Engineering and Governance ProblemA useful security model begins with three objectives: confidentiality, integrity, and availability. Confidentiality prevents unauthorized disclosure; integrity protects information and behavior from unauthorized modification; availability ensures that legitimate users can obtain services when needed. These objectives are supported by authenticity, accountability, non-repudiation where appropriate, and resilience. Security controls should be selected through risk analysis. A threat is a potential cause of harm, a vulnerability is a weakness that can be exploited, and risk combines the likelihood and impact of an adverse event. Risk treatment may involve reducing, transferring, avoiding, or accepting risk. Acceptance should be an explicit, authorized decision rather than the accidental result of an incomplete implementation. Secure engineering commonly follows principles such as least privilege, defense in depth, fail-safe defaults, secure by design, separation of duties, complete mediation, economy of mechanism, and minimizing attack surface. For example, a service account should have only the database permissions required by its operations. A failed authorization check should deny access rather than silently continue. A production service should not expose administrative endpoints merely because they are convenient during development. Threat modeling makes these principles concrete. The team identifies assets, trust boundaries, actors, entry points, abuse cases, and possible mitigations. STRIDE is one useful model for categorizing spoofing, tampering, repudiation, information disclosure, denial of service, and elevation of privilege. Threat modeling is not a one-time diagramming exercise; significant architectural and dependency changes should trigger review. Identity, Authentication, and AuthorizationAuthentication answers the question, “Who or what is acting?” Authorization answers, “What is that identity allowed to do?” Accounting and auditing answer, “What happened, when, and with what result?” Confusing these functions produces serious defects. A valid login does not imply permission to read every record. Authentication may use knowledge factors such as passwords, possession factors such as hardware security keys, and inherence factors such as biometrics. Strong systems use multifactor authentication for high-impact operations. Passwords should be long, rate-limited, protected against automated guessing, and stored only as salted, computationally expensive password hashes. Password encryption is not an adequate substitute for one-way password hashing because an application that can decrypt passwords has unnecessarily retained the original secret. In Java, password hashing should use a recognized password-hashing library or a well-reviewed implementation of algorithms such as Argon2id, scrypt, or bcrypt, with parameters selected for the deployment environment. General-purpose hashes such as SHA-256 are unsuitable for password storage without a password-specific work factor and salt. Password reset tokens should be random, short-lived, single-use, and stored or compared in a way that limits exposure. Session identifiers and bearer tokens must be generated with a cryptographically secure random source. Web sessions should use secure, HttpOnly, and appropriately scoped cookies, with protection against session fixation and cross-site request forgery. Access tokens should have limited lifetime and scope. Refresh tokens require stronger protection and revocation strategy. JWTs are not automatically secure: signature verification, issuer and audience validation, algorithm restrictions, expiry checks, and key management remain necessary. Authorization can be role-based, attribute-based, relationship-based, or policy-based. Role-based access control is useful where permissions align with stable organizational roles. Attribute-based authorization evaluates attributes such as user, resource, action, location, or risk context. Object-level authorization is especially important in APIs: a user authorized to access the endpoint may still be unauthorized to access the particular object identified by an identifier in the request. A robust authorization design centralizes policy where practical, checks access on every relevant request, denies by default, and tests both permitted and prohibited paths. Client-side hiding of a button is not authorization. Authorization must be enforced on the trusted server side. Cryptography: Selecting Controls Rather Than Inventing ThemCryptography provides mechanisms for confidentiality, integrity, authentication, and digital signatures, but it does not repair a flawed security design. Developers should use established Java cryptographic APIs and maintained libraries rather than inventing algorithms, protocols, or key-management schemes. Symmetric encryption uses one secret key for encryption and decryption. Authenticated encryption, such as AES-GCM or ChaCha20-Poly1305, provides confidentiality and integrity together. Each encryption operation requires a unique nonce under the same key; nonce reuse can seriously compromise security. Randomized encryption does not remove the need for key rotation, access control, backup protection, and lifecycle management. Asymmetric cryptography uses a key pair. Public-key encryption can protect information for a recipient, while digital signatures allow a verifier to establish that data was signed by the holder of a private key and was not altered. In practice, systems often use hybrid encryption: asymmetric mechanisms establish or protect a symmetric key, which handles bulk data efficiently. TLS protects data in transit when correctly configured. Certificate validation must not be disabled to “solve” connectivity problems. Trust stores, certificate rotation, hostname verification, protocol versions, and cipher configuration belong to operational governance as well as code. Sensitive data at rest may require encryption, but encryption keys should not be stored beside the encrypted data without an independent protection strategy. Keys have an identifiable lifecycle: generation, distribution, storage, use, rotation, revocation, backup, and destruction. A key-management service or hardware-backed facility is preferable to keys embedded in source code or configuration files. Cryptographic randomness should come from `SecureRandom`, not predictable pseudo-random generators. Constant-time comparison may be required for sensitive authentication values to reduce timing leakage. Input Validation and Safe Data HandlingAll external input should be treated as untrusted, including HTTP parameters, JSON documents, files, message queues, database records imported from other systems, and environment values. Validation should occur at trust boundaries and should reflect the expected type, length, range, encoding, and business constraints. Allow-list validation is generally stronger than attempting to enumerate every malicious value. A date field should be parsed as a date; an integer should be parsed and range-checked; an identifier should conform to an explicitly defined format. Canonicalization matters because different encodings or representations may bypass checks. Validation must not be used as the only defense against injection. Parameterized queries or prepared statements prevent SQL injection by separating data from query structure. Output encoding must be appropriate to the target context, such as HTML, JavaScript, URL, SQL, or a shell command. A string safe in one context may be dangerous in another. Where possible, avoid invoking operating-system commands; if unavoidable, use safe process APIs, fixed commands, constrained arguments, and strict authorization. File uploads require limits on size and type, safe generated names, storage outside executable paths, malware scanning where appropriate, and protection against path traversal. XML processing should disable unsafe external entity behavior when XML is required. Error responses should provide useful information to legitimate operators without disclosing stack traces, secrets, database details, or internal topology to attackers. Secrets, Configuration, and PrivacySecrets include passwords, private keys, API tokens, signing keys, database credentials, and sensitive connection information. They should not appear in source code, version control, container images, logs, screenshots, or ordinary issue discussions. Secret managers can provide controlled storage, access policies, rotation, audit trails, and short-lived credentials. Configuration should be separated from application logic, but external configuration is not automatically safe. Environment variables may be exposed through process inspection, diagnostics, or deployment systems. Access to configuration must therefore be controlled and monitored. Developers should establish a process for detecting leaked secrets, revoking them promptly, and investigating the exposure. Privacy engineering addresses how personal data is collected, used, shared, retained, and deleted. Important practices include data minimization, purpose limitation, accuracy, retention controls, access transparency, pseudonymization where suitable, and privacy-preserving defaults. Encryption does not eliminate privacy obligations. A system can encrypt a database and still collect excessive data, retain it indefinitely, or expose it through logs. Logging requires particular care. Logs should support incident investigation and operational accountability, but should not contain passwords, access tokens, full payment information, unnecessary personal identifiers, or sensitive request bodies. Access to logs is itself a security and privacy concern. Retention periods and deletion procedures should be defined rather than left to uncontrolled storage growth. Deserialization and Object Construction RisksDeserialization converts an external representation into an object graph. Insecure deserialization can permit unexpected classes, gadget chains, denial of service, data corruption, or remote code execution, depending on the technology and available classes. Java native serialization is especially risky when it processes untrusted or insufficiently trusted input. The safest approach is to avoid native object deserialization for untrusted data. Prefer constrained data formats such as JSON, Protocol Buffers, or other explicitly modeled representations, and map incoming data into simple data-transfer objects. Even then, parsers must be configured safely, input sizes limited, and types validated. If deserialization cannot be avoided, use strict allow-lists, filtering mechanisms, signed or authenticated data where appropriate, isolation, resource limits, and continuous dependency monitoring. Type metadata supplied by an attacker must not determine arbitrary class construction. A signature alone does not solve all problems if signing keys are compromised or if signed content is accepted without authorization and freshness checks. Dependency and Software Supply-Chain SecurityModern Java systems depend on frameworks, libraries, build plugins, container images, and transitive components. A vulnerability may enter through a dependency the application team never directly selected. Dependency security therefore requires inventory, version governance, vulnerability monitoring, timely patching, and testing for compatibility. Build tools such as Maven and Gradle should use controlled repositories, dependency locking or version constraints, reviewable build files, and reproducible or verifiable builds where feasible. Teams should distinguish direct from transitive dependencies and remove unused components. Automated scanners are valuable but cannot replace human risk assessment: a reported vulnerability may be unreachable in a particular configuration, while an unreported design weakness may still be serious. A software bill of materials (SBOM) is a machine-readable inventory of components, versions, suppliers, and relationships in a software artifact. Formats such as SPDX and CycloneDX support different governance and exchange needs. An SBOM helps an organization determine exposure when a component vulnerability is announced, but it is not itself proof that the software is secure. It must be accurate, maintained, connected to deployed artifacts, and complemented by vulnerability intelligence and remediation processes. Supply-chain controls include signed artifacts, protected branches, code review, multi-factor authentication for publishing, isolated build workers, provenance records, dependency pinning, secret scanning, and separation between build and release authority. A compromised build pipeline can defeat otherwise secure application code. Organizations should know who can modify source, dependencies, build definitions, release artifacts, and deployment configuration. Licensing is also part of supply-chain governance. Open-source software is not “free of obligations.” Licenses may impose notice, attribution, source-disclosure, patent, or redistribution conditions. A software composition review should record license identity, compatibility with the intended distribution model, and any required notices. Legal review is appropriate for ambiguous or high-impact cases. Secure Coding Standards, Testing, and AuditabilitySecure coding standards convert principles into repeatable development practices. A Java standard may address exception handling, input validation, cryptographic APIs, logging, concurrency, dependency use, resource management, and prohibited constructs. Standards should be specific enough to guide code review and flexible enough to be updated as threats and platforms evolve. Security activities should occur throughout the development life cycle. Requirements may define authentication assurance, privacy constraints, retention, and audit needs. Design reviews and threat models expose architectural weaknesses. Code review identifies unsafe APIs and authorization gaps. Static application security testing, software composition analysis, dynamic testing, fuzzing, and penetration testing provide complementary evidence. No single tool detects every vulnerability. Auditability is the capacity to reconstruct significant actions and decisions. Security logs should record an event, actor or service identity, target, time, outcome, correlation identifier, and relevant context, while avoiding unnecessary sensitive data. Time synchronization, tamper resistance, restricted access, retention, and alerting determine whether logs are useful. An audit trail is not merely a debug log; it is evidence supporting accountability, incident response, compliance, and forensic analysis. Security testing should include negative cases: expired tokens, altered identifiers, malformed input, unauthorized roles, replay attempts, rate-limit exhaustion, and dependency failure. Tests should verify that access is denied where it should be denied. Continuous integration can enforce dependency policies, secret detection, signed commits or artifacts where required, and security regression tests. Governance, Responsibility, and Ethical PracticeGovernance establishes who decides, who implements, who verifies, and who accepts residual risk. A security program typically defines policies, control ownership, exception procedures, risk registers, incident response, supplier assessment, training, and periodic review. Technical teams should be able to explain not only that a control exists, but also its purpose, evidence, owner, and failure response. Regulatory obligations vary by jurisdiction and sector, but common concerns include protection of personal data, breach notification, records management, financial controls, accessibility, and sector-specific security requirements. Compliance should not be treated as equivalent to security. A compliant system can still be poorly designed, and a strong technical control may still require documentation or lawful processing. Ethical security practice respects user autonomy, confidentiality, and safety. Engineers should not collect data merely because collection is technically possible. They should disclose material risks, avoid deceptive security claims, protect confidential information, and report vulnerabilities through responsible channels. Security research requires authorization and proportionality; testing a real system without permission can harm users and violate law or professional duties. When a vulnerability is discovered, organizations should assess exploitability and impact, contain immediate risk, develop and test remediation, communicate appropriately, and preserve evidence. Suppressing a serious known risk to protect schedules or reputation is an ethical failure. Conversely, public disclosure without giving affected parties a reasonable opportunity to respond can create avoidable harm. Professional judgment must balance transparency, safety, and accountability. Illustrative Case Study: A Vulnerable University Research PortalBackgroundA university research portal is implemented as a Java REST service. It stores researcher profiles, grant documents, and collaboration records. The portal uses a popular web framework, a relational database, cloud object storage, and several open-source libraries. Situation and ProblemA security review finds that users can change an object identifier in a download request and retrieve another researcher’s document. The application stores database credentials in a source-controlled configuration file. A legacy endpoint accepts Java serialized objects from an integration partner. Logs contain access tokens, and the build uses unpinned transitive dependencies. The system has login functionality, but no documented authorization model or SBOM. AnalysisThe object download defect is an object-level authorization failure: authentication is present, but authorization is not checked against the requested resource. The credential exposure creates immediate risk because anyone with repository access may access the database. Native deserialization creates a potentially severe attack surface, while unpinned dependencies reduce the organization’s ability to identify and reproduce the deployed software. Token logging increases the impact of account compromise and creates a privacy problem. The issues are connected. Weak governance allowed secrets, dependencies, and legacy interfaces to escape normal review. The absence of an asset and data classification model made it difficult to determine which records required stronger controls. The portal’s operational evidence was also inadequate for determining whether unauthorized downloads had already occurred. Approach and StrategyThe response begins with containment. Database credentials are revoked and replaced through a secret-management mechanism. Existing sessions and tokens are invalidated, and access logs are preserved. The vulnerable download endpoint is temporarily restricted while the team investigates exposure. The team then defines an authorization policy: a researcher may download a document only when an explicit relationship exists between the authenticated identity, the research project, and the document. The policy is enforced on the server, tested with positive and negative cases, and reviewed independently. Identifiers are no longer treated as permission grants. The legacy serialized endpoint is replaced with a versioned JSON contract using constrained data-transfer objects and size limits. Dependency versions are reviewed, vulnerable components upgraded or removed, and the build is configured to generate an SBOM associated with each release artifact. Repository access is reduced, publishing requires stronger authentication, and build logs are checked for secrets. Logging is redesigned to record identity, action, object category, outcome, and correlation identifier without recording bearer tokens or document contents. The team establishes retention and access rules, adds alerts for unusual download patterns, and performs a retrospective search for suspicious activity. A threat model, data inventory, secure coding standard, and incident response procedure are added to the project governance record. OutcomeThe immediate vulnerabilities are mitigated, and the portal gains a repeatable release process. The university can identify the components in each deployment, demonstrate who approved changes, and investigate document access more effectively. Some convenience is lost: integrations require explicit contracts, releases take longer, and researchers occasionally complete additional verification. However, the system’s trustworthiness and maintainability improve. Learning PointsThe case demonstrates that secure engineering is not a single patch. Authentication without authorization is inadequate; encryption cannot compensate for poor key governance; a dependency inventory supports but does not replace risk analysis; and auditability must be designed with privacy in mind. Most importantly, technical controls become durable only when embedded in ownership, workflow, and organizational decision-making. Challenges and Common MistakesSeveral recurring mistakes undermine Java security: - Treating framework defaults as a complete security architecture.
- Writing custom encryption, token, or password mechanisms.
- Checking authorization only at the user-interface layer.
- Logging secrets for debugging and failing to remove them.
- Assuming that an SBOM or scanner report alone establishes security.
- Accepting serialized or polymorphic input without strict type control.
- Upgrading dependencies blindly without testing, or delaying all upgrades until a crisis.
- Treating privacy as a legal document rather than a system-design concern.
- Granting broad service-account permissions for operational convenience.
- Making security exceptions permanent because they were initially labeled temporary.
Security also has limitations. Controls introduce cost, latency, usability friction, false positives, and maintenance obligations. Strong authentication can exclude users if recovery is poorly designed. Excessive logging can create privacy risk. Automated tools may miss business-logic flaws. Effective governance therefore requires proportionate controls, measurable outcomes, and periodic reassessment rather than indiscriminate restriction. Current Developments and Strategic DirectionsCloud-native Java systems increasingly use short-lived workloads, service identities, API gateways, managed secrets, and automated delivery pipelines. These environments make identity, provenance, and policy enforcement more important than network location alone. Zero-trust approaches emphasize continuous verification, explicit authorization, least privilege, and limited implicit trust. Software supply-chain regulation and procurement requirements are increasing attention to SBOMs, provenance, vulnerability disclosure, and supplier accountability. Memory-safe languages are also influencing architectural choices, although Java’s managed memory does not eliminate application-level vulnerabilities such as injection or authorization errors. Artificial intelligence can assist with code review, vulnerability triage, dependency analysis, and anomaly detection. It can also generate insecure code, reproduce flawed patterns, expose sensitive prompts, or create unjustified confidence. AI-generated Java code must undergo the same threat modeling, review, testing, licensing checks, and human accountability as manually written code. Automation should improve evidence and consistency, not transfer responsibility away from engineers. Best-Practice Decision FrameworkA practical secure Java program can be organized around six questions: 1. What must be protected? Identify data, functions, identities, dependencies, keys, and operational assets. 2. Who can act, and under what conditions? Define authentication assurance and object-level authorization. 3. What can be trusted? Mark boundaries and validate every external representation. 4. How will failure be contained? Apply least privilege, isolation, rate limits, safe defaults, and incident response. 5. What evidence will be available? Maintain audit trails, SBOMs, release provenance, test results, and risk decisions. 6. Who is accountable? Assign owners for controls, exceptions, privacy, suppliers, remediation, and disclosure. This framework supports both technical implementation and managerial review. It also helps teams distinguish a security feature from a security capability: a token-validation library is a feature; a governed identity lifecycle with tested policies, monitoring, and incident response is a capability. Chapter SummarySecure Java engineering combines application security, cryptography, identity management, privacy, supply-chain controls, and organizational governance. Authentication establishes identity, while authorization determines permitted actions and must be enforced on trusted server-side paths. Cryptography should rely on established algorithms, secure randomness, authenticated encryption, sound key management, and correctly configured TLS. External input requires validation, contextual output encoding, parameterized queries, safe file and XML handling, and controlled object construction. Secrets belong in managed systems rather than source code or logs. Native deserialization of untrusted data should be avoided. Dependencies require monitoring, controlled builds, vulnerability assessment, licensing review, provenance, and accurate SBOMs. Secure coding standards, threat modeling, code review, automated testing, auditability, and incident response convert security principles into repeatable practice. Privacy and ethics require data minimization, responsible disclosure, honest risk communication, and respect for users. The strategic objective is not absolute security, which is unattainable, but informed risk reduction supported by evidence, accountability, and continuous improvement. Key TermsAuthentication: The process of verifying the identity of a user, service, or device. Authorization: The decision about whether an authenticated identity may perform a particular action. Auditability: The ability to reconstruct significant actions, decisions, and outcomes from trustworthy evidence. Least privilege: Granting only the permissions necessary for an identity or component to perform its function. Threat model: A structured analysis of assets, trust boundaries, threats, vulnerabilities, and mitigations. Authenticated encryption: Encryption that provides confidentiality and integrity, usually through a combined algorithm and mode. Nonce: A value intended for one-time use in a cryptographic operation. Secret: Sensitive authentication or cryptographic material requiring controlled protection. Input validation: Checking external data against expected type, format, range, size, and business rules. Deserialization: Converting a data representation into an in-memory object or object graph. Gadget chain: A sequence of existing program behaviors that can be combined during unsafe deserialization. Dependency: An external library, framework, plugin, or component required by software. SBOM: A machine-readable inventory of software components and their relationships. Software provenance: Evidence describing how, where, and by whom a software artifact was produced. Supply-chain security: Protection of source, dependencies, build systems, artifacts, and distribution processes. Data minimization: Collecting and retaining only the personal data necessary for a defined purpose. Defense in depth: Using multiple complementary controls so that one failure does not expose the whole system. Residual risk: Risk remaining after controls have been implemented. Secure coding standard: An agreed set of development rules intended to prevent and detect security weaknesses. Review QuestionsShort Answer Questions1. Distinguish authentication from authorization and provide one Java application example of each. 2. Why are general-purpose hash functions unsuitable for direct password storage? 3. What is the purpose of an SBOM? 4. State two risks of logging access tokens. 5. Why should untrusted Java serialized data generally be avoided? Long Answer Questions1. Explain how threat modeling, least privilege, defense in depth, and auditability work together in secure Java engineering. 2. Discuss the complete lifecycle of cryptographic keys and the consequences of poor key management. 3. Explain how a Java organization should govern direct and transitive dependencies, SBOMs, licenses, and build provenance. 4. Describe a secure authorization design for a REST API that serves user-owned documents. 5. Examine the relationship between privacy engineering, logging, retention, and incident response. Analytical / Application Questions1. A Java service verifies a valid JWT but allows the caller to request any customer record by changing an identifier. Identify the vulnerability and design a corrective control and test strategy. 2. A build pipeline reports a critical vulnerability in a transitive library, but the affected code appears unused. What evidence should the team collect before accepting, mitigating, or remediating the risk? 3. A team proposes storing encrypted API keys in application properties committed to a private repository. Evaluate the proposal and recommend a secure alternative, including rotation and audit requirements. 22. Multiple Choice Questions with AnswersQuestion 1A user is successfully authenticated to a Java REST API but changes a document ID in the request and receives another user’s document. What control is missing? A. Transport-layer encryption B. Object-level authorization C. Password hashing D. Dependency pinning Correct Answer: B. Object-level authorization Question 2Which approach is most appropriate for storing user passwords? A. Reversible encryption with a database key B. Plain SHA-256 without a salt C. A salted, work-factor-based password-hashing algorithm D. Base64 encoding Correct Answer: C. A salted, work-factor-based password-hashing algorithm Question 3Why is nonce uniqueness important when using AES-GCM? A. It increases password length B. Nonce reuse can compromise confidentiality and integrity C. It removes the need for key rotation D. It authenticates users automatically Correct Answer: B. Nonce reuse can compromise confidentiality and integrity Question 4Which practice best protects against SQL injection in Java? A. Concatenating escaped strings manually B. Using prepared statements with parameter binding C. Encrypting the database backup D. Hiding database error messages only Correct Answer: B. Using prepared statements with parameter binding Question 5What is the primary purpose of an SBOM? A. To replace all security testing B. To list software components and support exposure analysis C. To encrypt application data D. To authorize API requests Correct Answer: B. To list software components and support exposure analysis Question 6Which is the safest general strategy for untrusted Java object input? A. Accept native serialization from any client B. Allow the client to choose arbitrary class names C. Use a constrained data format and map it to controlled DTOs D. Disable logging during deserialization Correct Answer: C. Use a constrained data format and map it to controlled DTOs Question 7Which item should normally not appear in application logs? A. A correlation identifier B. The authorization bearer token C. The request outcome D. The authenticated service identity Correct Answer: B. The authorization bearer token Question 8A dependency scanner reports a vulnerability in a transitive library. What is the most responsible first response? A. Ignore it because the library was not selected directly B. Delete all dependency records C. Assess reachability, impact, version, exposure, and remediation options D. Disable the scanner Correct Answer: C. Assess reachability, impact, version, exposure, and remediation options Question 9Which statement best describes privacy engineering? A. Encrypting data eliminates privacy obligations B. Collecting all potentially useful data is preferable C. Privacy includes minimization, purpose limitation, retention, and controlled access D. Privacy applies only after a breach Correct Answer: C. Privacy includes minimization, purpose limitation, retention, and controlled access Question 10Which practice most directly supports trustworthy software supply-chain security? A. Using unpinned dependencies for faster updates B. Allowing one person to modify source, build, and release systems without review C. Protecting build systems and recording artifact provenance D. Relying exclusively on client-side validation Correct Answer: C. Protecting build systems and recording artifact provenance
|