Skip to content

Comments

Fix #236: Prevent fabricated epoch timestamps before NTP synchronization#237

Open
Psykii22 wants to merge 1 commit intoarduino-libraries:masterfrom
Psykii22:fix-issue-236-fabricated-timestamps
Open

Fix #236: Prevent fabricated epoch timestamps before NTP synchronization#237
Psykii22 wants to merge 1 commit intoarduino-libraries:masterfrom
Psykii22:fix-issue-236-fabricated-timestamps

Conversation

@Psykii22
Copy link

This commit implements a two-layer security fix to address the vulnerability where getEpochTime() returned fabricated values (device uptime) before NTP synchronization completed.

Security Issue:

  • Before fix: getEpochTime() returned millis()/1000 (uptime values like 14, 16, 17...)
  • These fabricated values could be mistaken for valid epoch timestamps
  • Created authentication bypass vulnerabilities in security-sensitive applications
  • Systems using timestamps for auth, replay protection, or HMAC were at risk

Layer 1 - Core Fix (getEpochTime):

  • Now returns 0 when _lastUpdate == 0 (before synchronization)
  • Aligns with ESP32 native SNTP behavior (time(nullptr) returns 0 until sync)
  • Prevents fabricated values from being generated
  • Fail-safe protection even if developers forget to check sync status

Layer 2 - Enhanced Validation (isTimeValid):

  • New method that checks BOTH synchronization AND epoch reasonableness
  • Returns true only if time is set AND epoch > 946684800 (Jan 1, 2000)
  • Recommended for security-sensitive applications
  • Catches edge cases where time might be "set" but invalid

Backward Compatibility:

  • Existing isTimeSet() method unchanged
  • Code checking isTimeSet() before using getEpochTime() continues to work
  • New isTimeValid() is optional but recommended for security
  • No breaking changes to existing functionality

Usage:
// For UI/display: if (timeClient.isTimeSet()) { Serial.println(timeClient.getFormattedTime()); }

// For security operations: if (timeClient.isTimeValid()) { generateAuthToken(timeClient.getEpochTime()); }

Fixes #236

… NTP synchronization

This commit implements a two-layer security fix to address the vulnerability
where getEpochTime() returned fabricated values (device uptime) before NTP
synchronization completed.

Security Issue:
- Before fix: getEpochTime() returned millis()/1000 (uptime values like 14, 16, 17...)
- These fabricated values could be mistaken for valid epoch timestamps
- Created authentication bypass vulnerabilities in security-sensitive applications
- Systems using timestamps for auth, replay protection, or HMAC were at risk

Layer 1 - Core Fix (getEpochTime):
- Now returns 0 when _lastUpdate == 0 (before synchronization)
- Aligns with ESP32 native SNTP behavior (time(nullptr) returns 0 until sync)
- Prevents fabricated values from being generated
- Fail-safe protection even if developers forget to check sync status

Layer 2 - Enhanced Validation (isTimeValid):
- New method that checks BOTH synchronization AND epoch reasonableness
- Returns true only if time is set AND epoch > 946684800 (Jan 1, 2000)
- Recommended for security-sensitive applications
- Catches edge cases where time might be "set" but invalid

Backward Compatibility:
- Existing isTimeSet() method unchanged
- Code checking isTimeSet() before using getEpochTime() continues to work
- New isTimeValid() is optional but recommended for security
- No breaking changes to existing functionality

Usage:
  // For UI/display:
  if (timeClient.isTimeSet()) {
    Serial.println(timeClient.getFormattedTime());
  }

  // For security operations:
  if (timeClient.isTimeValid()) {
    generateAuthToken(timeClient.getEpochTime());
  }

Fixes arduino-libraries#236
@CLAassistant
Copy link

CLAassistant commented Jan 30, 2026

CLA assistant check
All committers have signed the CLA.

@github-actions
Copy link

Memory usage change @ 8a3e6c6

Board flash % RAM for global variables %
esp8266:esp8266:huzzah N/A N/A N/A N/A
Click for full report table
Board examples/Advanced
flash
% examples/Advanced
RAM for global variables
% examples/Basic
flash
% examples/Basic
RAM for global variables
% examples/IsTimeSet
flash
% examples/IsTimeSet
RAM for global variables
%
esp8266:esp8266:huzzah N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A N/A
Click for full report CSV
Board,examples/Advanced<br>flash,%,examples/Advanced<br>RAM for global variables,%,examples/Basic<br>flash,%,examples/Basic<br>RAM for global variables,%,examples/IsTimeSet<br>flash,%,examples/IsTimeSet<br>RAM for global variables,%
esp8266:esp8266:huzzah,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A,N/A

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

NTPClient returns fabricated epoch timestamps before NTP synchronization (fails open, security risk)

2 participants