Skip to content

fix: restrict future dates in mark attendance - #4950

Open
nareshkannasln wants to merge 2 commits into
frappe:developfrom
aerele:guard-future-bulk-attendance
Open

fix: restrict future dates in mark attendance#4950
nareshkannasln wants to merge 2 commits into
frappe:developfrom
aerele:guard-future-bulk-attendance

Conversation

@nareshkannasln

Copy link
Copy Markdown
Contributor

Description: The Mark Attendance dialog only greyed out future dates in the to_date datepicker. That's UI-only — ControlDate.validate() checks the date format, not the range — so a future date could still be typed in. Behind it the server had no guard at all: get_unmarked_days() offered future dates as options, and mark_bulk_attendance() marked whatever dates it was sent.

Before:

Screencast.from.2026-07-16.20-42-03.webm

After:

Screencast.from.2026-07-16.20-39-53.webm

Backport needed for v15, v16

@nareshkannasln
nareshkannasln marked this pull request as ready for review July 16, 2026 15:32
@greptile-apps

greptile-apps Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

Both the UI and server-side paths are now guarded against future dates; the change is minimal and targeted.

The two-line Python changes close a clear gap — get_unmarked_days now clamps to today, and mark_bulk_attendance rejects future dates before any DB write. The JS change is defensive-in-depth only. No unrelated logic is touched.

No files require special attention.

Reviews (3): Last reviewed commit: "chore: use getdate() and compute today o..." | Re-trigger Greptile

Comment on lines +86 to +110
def bulk_assign(self, employees: list):
validate_bulk_tool_fields(self, ["company", "holiday_list"], employees)

if len(employees) <= 30:
return self._bulk_assign(employees)

frappe.enqueue(self._bulk_assign, timeout=3000, employees=employees)
frappe.msgprint(
_("Assignment of Holiday List has been queued. It may take a few minutes."),
alert=True,
indicator="blue",
)

def _bulk_assign(self, employees: list):
success, failure = [], []
count = 0
savepoint = "before_holiday_list_assignment"

for d in employees:
try:
frappe.db.savepoint(savepoint)
employee = frappe.get_doc("Employee", d)
employee.holiday_list = self.holiday_list
employee.save()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Scope bypass in bulk_assign: _bulk_assign iterates over the client-supplied employees list without re-validating it against the get_employees() scope. An HR User scoped to Company X can call bulk_assign with an employee ID from Company Y; validate_bulk_tool_fields only checks required fields, not company/department boundary, and frappe.get_doc("Employee", d) loads the record without check_permission=True (contrast with hrms/hr/utils.py:174 which explicitly passes it). The save then writes the out-of-scope employee's holiday list.

How this was verified: Static source-to-sink trace: the attacker-controlled employees RPC parameter reaches frappe.get_doc("Employee", d)employee.save() with no re-query against the match-conditions applied in get_employees. Concrete exploit: user with Company X scope sends employees=["EMP099"] (Company Y record); _bulk_assign accepts and persists the assignment.

@nareshkannasln
nareshkannasln force-pushed the guard-future-bulk-attendance branch from 2aa9b6b to e548f5e Compare July 16, 2026 15:42
@mergify

mergify Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@asmitahase

asmitahase commented Jul 17, 2026

Copy link
Copy Markdown
Member

We don't exactly restrict future attendance marking anywhere. This change seems unnecessary.

@nareshkannasln

Copy link
Copy Markdown
Contributor Author

We don't exactly restrict future attendance marking anywhere. This change seems unnecessary.

In the Mark Attendance dialog, the to_date field already prevents users from selecting future dates through the date picker, the future dates are disabled (greyed out). However, users can still manually enter or modify the date value. I added this validation to prevent manually entering a future date, so the behavior remains consistent regardless of how the value is provided.

@asmitahase

Copy link
Copy Markdown
Member

Then maybe we should take the out the max date in date picker as well

@nareshkannasln

Copy link
Copy Markdown
Contributor Author

Then maybe we should take the out the max date in date picker as well

If we remove the max_date restriction, users will be able to explicitly select future dates and mark attendance as Present. I'm not sure if that's the intended behavior.

Also, there doesn't seem to be any validation in the Attendance DocType to prevent marking Present for a future date.

If the expected behavior is to disallow future attendance for the Present status, we can add a conditional validation to throw an error when the attendance date is in the future, the status is Present, and the attendance is not linked to an Attendance Request. This will ensure the restriction is enforced consistently.

Also, are there any scenarios where marking Present attendance for a future date is expected or allowed?

@nareshkannasln
nareshkannasln marked this pull request as draft July 21, 2026 11:12
@nareshkannasln
nareshkannasln marked this pull request as ready for review July 21, 2026 11:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants