Security Model
NullGraph implements multiple layers of security controls at both the on-chain program and frontend levels. This page documents the security architecture, protection mechanisms, and implementation details.On-Chain Security Architecture
The Solana program (lib.rs) implements defense-in-depth security controls across all instructions and account operations.
Signer Authentication
Every write instruction enforces strict signer validation through Anchor’s account struct constraints:lib.rs:283- InitializeProtocollib.rs:303- SubmitNullResultlib.rs:331- CreateBountylib.rs:376- SubmitToBountylib.rs:405- ApproveBountySubmissionlib.rs:445- CloseBounty
PDA Ownership Validation
All data accounts are program-owned PDAs (Program Derived Addresses) with deterministic seeds. This prevents:- Account spoofing attacks
- Cross-program account injection
- Unauthorized account creation
| Account | Seeds | Location |
|---|---|---|
| ProtocolState | ["protocol_state"] | lib.rs:289 |
| NullResult | ["null_result", researcher_pubkey, specimen_number] | lib.rs:316-320 |
| NullBounty | ["null_bounty", creator_pubkey, bounty_number] | lib.rs:344-348 |
| BountyVault | ["bounty_vault", bounty_pda] | lib.rs:358 |
| BountySubmission | ["bounty_submission", bounty_pda, null_result_pda] | lib.rs:390-394 |
init constraint, which automatically validates that accounts don’t already exist and are owned by the program.
Authorization Constraints
The program enforces ownership and authority checks using Anchor’shas_one constraint:
- Only the NKA researcher can submit it to bounties (
lib.rs:379) - Only the bounty creator can approve submissions (
lib.rs:409) - Only the bounty creator can close bounties and reclaim funds (
lib.rs:449)
State Machine Guards
All instructions validate current state before allowing transitions:| Account Type | Status | Value | Allowed Transitions |
|---|---|---|---|
| NullResult | Pending | 0 | → Verified, Disputed |
| NullResult | Verified | 1 | Final state |
| NullResult | Disputed | 2 | Final state |
| NullBounty | Open | 0 | → Matched, Closed |
| NullBounty | Matched | 1 | → Fulfilled, Closed |
| NullBounty | Fulfilled | 2 | Final state |
| NullBounty | Closed | 3 | Final state |
| BountySubmission | Pending | 0 | → Approved, Rejected |
| BountySubmission | Approved | 1 | Final state |
| BountySubmission | Rejected | 2 | Final state |
Replay Attack Prevention
The PDAinit constraint provides automatic replay protection:
- Each NKA can only be submitted to a bounty once (unique PDA per bounty-NKA pair)
- Researchers cannot create duplicate NKAs (unique PDA per researcher + specimen number)
- Bounties cannot be created with duplicate numbers (sequential counter + unique PDA)
- Protocol can only be initialized once (singleton PDA)
Vault Authority and Token Security
Bounty vault token accounts use the vault PDA itself as authority, ensuring only CPI transfers with correct seeds:No user wallet can sign for vault transfers. Only the program can authorize token movements through CPI with valid PDA seeds.
Safe Arithmetic Operations
All fee and payout calculations use checked arithmetic to prevent overflow/underflow:- Fee calculation:
reward_amount * fee_bps / 10_000(lib.rs:169-173) - Payout calculation:
reward_amount - fee(lib.rs:174) - Counter increments:
state.nka_counter += 1(Rust panic on overflow in debug mode)
Transfer Validation
All token transfers usetransfer_checked, which validates mint address and decimal precision:
Using
transfer_checked instead of transfer prevents token decimal confusion attacks and mint spoofing.- Bounty creation escrow:
lib.rs:100-112 - Researcher payout:
lib.rs:185-198 - Treasury fee transfer:
lib.rs:202-216 - Bounty refund:
lib.rs:249-262
Input Validation
The program validates critical inputs before processing:- PDA bump validation (automatic via
bumpfield) - Account ownership validation (automatic via
Account<'info, T>) - Program ownership validation (automatic via
seedsconstraint)
Submission Matching Validation
The approval instruction validates that the correct submission is being approved:Frontend Security
The React frontend implements client-side security best practices:Private Key Protection
- No private keys are handled by the application
- All transaction signing delegated to Phantom wallet
- Uses Solana Wallet Adapter standard interface
Data Integrity
Client-side file hashing via Web Crypto API:lib.rs:60), providing tamper-proof data fingerprints without storing files on-chain.
Input Sanitization
All text inputs enforce length limits matching on-chain field sizes:- Hypothesis: 128 bytes max
- Methodology: 128 bytes max
- Expected/Actual Outcome: 128 bytes max each
- Bounty Description: 256 bytes max
RPC Security
- All RPC calls use HTTPS endpoints
- No sensitive data transmitted in RPC requests
- Read-only operations use standard
getProgramAccounts - Write operations require wallet signature
Known Limitations
Not Implemented
- Formal verification - No mathematical proof of correctness
- Professional security audit - No third-party review
- Fuzzing tests - Limited edge case coverage
- Rate limiting - No spam protection at protocol level
- Upgrade authority - No mechanism for bug fixes post-deployment
- Access control - No admin roles beyond initial authority
- Emergency pause - No circuit breaker for critical bugs
- Time-based controls - Deadline validation not enforced in all instructions
- Economic attack resistance - No analysis of MEV or front-running risks
- Dispute resolution - Status field exists but no enforcement mechanism
Production Requirements
Before production deployment:- Conduct formal security audit with reputable firm
- Implement comprehensive test suite with >90% coverage
- Add deadline validation to
submit_to_bountyinstruction - Implement admin controls and upgrade authority
- Add circuit breaker for emergency situations
- Conduct economic security analysis
- Implement dispute resolution workflow
- Add rate limiting at RPC level
- Deploy to testnet for extended period
- Bug bounty program
Security Contact
For security concerns or vulnerability reports, please contact the development team through appropriate channels.Never share private keys, seed phrases, or wallet credentials with anyone, including project maintainers.