NVIDIA Vera Rubin NVL72 Rack and More in the Pegatron booth at GTC 2026

Post Syndicated from Patrick Kennedy original https://www.servethehome.com/nvidia-vera-rubin-nvl72-rack-and-more-in-the-pegatron-booth-at-gtc-2026/

We saw the NVIDIA Vera Rubin NVL72 rack, CPUs, GPUs, networking, storage, and a lot more in the Pegatron booth at NVIDIA GTC 2026

The post NVIDIA Vera Rubin NVL72 Rack and More in the Pegatron booth at GTC 2026 appeared first on ServeTheHome.

Build a multi-tenant configuration system with tagged storage patterns

Post Syndicated from Koshal Agrawal original https://aws.amazon.com/blogs/architecture/build-a-multi-tenant-configuration-system-with-tagged-storage-patterns/

In modern microservices architectures, configuration management remains one of the most challenging operational concerns. Two gaps emerge as organizations scale: handling tenant metadata that changes faster than cache TTL allows, and scaling the metadata service itself without creating a performance bottleneck.

Traditional caching strategies force an uncomfortable trade-off: either accept stale tenant context (risking incorrect data isolation or feature flags), or implement aggressive cache invalidation that sacrifices performance and increases load on your metadata service. When tenant counts grow into the hundreds or thousands, this metadata service itself becomes a scaling challenge, particularly when different configuration types have vastly different access patterns.

The challenge intensifies when you need to support different storage backends for different configuration types. Some require high-frequency access patterns suited for Amazon DynamoDB, while others benefit from the hierarchical organization and built-in versioning of AWS Systems Manager Parameter Store. Traditional solutions often force engineering teams into a corner: either build multiple configuration services (increasing operational overhead), or compromise on performance by using a single storage backend that isn’t optimized for every use case.

In this post, we demonstrate how you can build a scalable, multi-tenant configuration service using the tagged storage pattern, an architectural approach that uses key prefixes (like tenant_config_ or param_config_) to automatically route configuration requests to the most appropriate AWS storage service. This pattern maintains strict tenant isolation and supports real-time, zero-downtime configuration updates through event-driven architecture, alleviating the cache staleness problem.

What you’ll learn:

  • Implementing a multi-tenant data model with DynamoDB and Parameter Store
  • Using the Strategy pattern for flexible storage backend switching
  • Building tenant isolation through JSON Web Token (JWT) claims
  • Creating an event-driven auto-refresh mechanism with Amazon EventBridge and AWS Lambda
  • Implementing zero-downtime configuration updates with gRPC (a high-performance communication protocol) streaming
  • Addressing the cache TTL problem for rapidly-changing tenant metadata

By the end of this post, you’ll understand how to architect a configuration service that handles complex multi-tenant requirements while optimizing for both performance and operational simplicity.

Solution overview

The architecture uses four AWS services orchestrated through a NestJS-based gRPC service to create a reliable, event-driven configuration management system. Let’s first understand the overall architecture before diving into each component’s implementation details.

Architecture components

The following diagram shows the end-to-end architecture of the Multi-Tenant Configuration Service deployed on AWS, from how client requests enter the system to how configuration data is retrieved from the right storage backend.

WS microservices architecture diagram showing ECS Fargate services, API Gateway, Cognito auth, DynamoDB, and CloudWatch monitoring

Figure 1: Multi-Tenant Configuration Service Architecture

Client applications authenticate via Amazon Cognito and pass through AWS WAF before reaching Amazon API Gateway. Traffic is then routed through a VPC Link to an Application Load Balancer, which distributes requests across two core microservices running on Amazon Elastic Container Service (Amazon ECS) on AWS Fargate within private subnets :

  • Order Service— handles incoming REST requests and delegates configuration lookups to the Config Service via gRPC
  • Config Service— exposes a gRPC API and uses a Config Strategy Factory to dynamically select the appropriate storage backend (DynamoDB or Parameter Store) based on the request

Service discovery is managed by AWS Cloud Map, while Amazon CloudWatch centralizes logs and metrics across services.

The system is organized into four interconnected layers, each addressing a specific aspect of the configuration management challenge:

1. Storage layer – multi-backend strategy

The storage layer strategically uses two complementary AWS services, each optimized for different configuration access patterns and requirements.

  • Amazon DynamoDB: Stores tenant-specific configurations. These are settings unique to each customer, such as payment gateway preferences or feature flags. With single-digit millisecond latency, DynamoDB handles high-frequency reads efficiently. The schema uses composite keys (TENANT#{tenantId} as partition key, CONFIG#{configType} as sort key) for efficient tenant-scoped queries and built-in multi-tenant isolation at the data model level.
  • AWS Systems Manager Parameter Store: manages shared parameters. These are configuration values used across multiple services or tenants, such as API endpoints, database connection strings, and region-specific settings. Unlike tenant-specific configs that change frequently, these parameters are relatively static but benefit from hierarchical organization. The path structure (/config-service/{tenantId}/{service}/{parameter}) enables bulk retrieval operations, reducing the number of API calls needed during service initialization from dozens to a single request.

2. Service layer – gRPC with strategy pattern

A NestJS-based microservice implements the configuration retrieval logic using gRPC for high-performance, type-safe communication. This choice significantly reduces network bandwidth and improves response times for service-to-service communication where compatibility with web browsers isn’t a requirement.

At the core is a Strategy Pattern implementation that determines the optimal storage backend based on configuration key prefixes. This pattern simplifies the addition of new storage backends (like Amazon Simple Storage Service (Amazon S3) for large configuration files) without modifying the core service logic.

3. Authentication layer – Amazon Cognito

User authentication flows through Amazon Cognito with custom attributes:

  • custom:tenantId (immutable) – Tenant identifier embedded in JWT
  • custom:role (mutable) – User role for authorization

Critical security design: The service never accepts tenantId from request parameters. Instead, it extracts the tenant context from validated JWT tokens, making sure requests cannot access other tenants’ data even if they attempt to manipulate request payloads.

4. Event-driven refresh layer

Traditional configuration updates present a dilemma: how do you keep services synchronized without compromising performance or causing downtime?

Polling approaches continuously check for changes, generating unnecessary API calls that cost money even when nothing changes. They also introduce delays. Services don’t see updates until the next poll cycle, which could be seconds or minutes later.

Service restart approaches cause downtime, drop active connections, and disrupt user sessions. For SaaS applications serving customers 24/7, restart-based updates are unacceptable.

The event-driven refresh layer addresses both problems by implementing a reactive architecture where Amazon EventBridge monitors Parameter Store for changes and triggers AWS Lambda to update the service’s local cache. This achieves configuration updates within seconds while users experience no interruption.

Technical implementation

The following sections detail the implementation, starting with the data model, which serves as the backbone for tenant isolation and efficient querying.

A. Multi-tenant data model

The foundation of tenant isolation begins with the data model. Using DynamoDB’s composite key structure, we achieve both tenant isolation and efficient querying without requiring separate tables per tenant.

DynamoDB schema design:

The following example shows a tenant-specific configuration stored in DynamoDB, illustrating how composite keys enable both isolation and efficient access:

{
  "pk": "TENANT#acme-corp",
  "sk": "CONFIG#payment-gateway",
  "config": {
    "providers": [
      {
        "name": "Stripe",
        "apiEndpoint": "https://api.stripe.com",
        "retryPolicy": "exponential"
      }
    ]
  },
  "isActive": true,
  "version": 2,
  "createdAt": "2024-01-15T10:30:00Z",
  "updatedAt": "2024-02-20T14:45:00Z"
}

Key schema decisions:

  1. Partition key pattern: TENANT#{tenantId} makes sure tenant data is co-located, enabling efficient tenant-scoped queries while maintaining logical separation.
  2. Sort key pattern: CONFIG#{configType} allows querying specific configuration types within a tenant’s data. The CONFIG# prefix enables future expansion with other entity types (for example, METADATA#, AUDIT#).
  3. Soft deletion: The isActive boolean flag supports soft deletion, maintaining audit trails while excluding inactive configurations from queries.
  4. Versioning: The version field tracks configuration changes, supporting rollback capabilities and change history.

Parameter store organization:

Parameters follow a hierarchical structure that mirrors the multi-tenant model. This example demonstrates the path structure:

/config-service/
├── acme-corp/
│   ├── api/
│   │   ├── api-key
│   │   └── endpoint
│   └── database/
│       └── connection-string
└── globex-inc/
    ├── api/
    │   ├── api-key
    │   └── endpoint
    └── database/
        └── connection-string

This structure provides several benefits:

  • Bulk retrieval using path prefix (GetParametersByPath API)
  • Clear ownership and access control through AWS Identity and Access Management (AWS IAM) policies
  • Environment separation (dev/staging/prod) at the path level
  • Automatic parameter versioning and change tracking

Advanced: Multi-dimensional tenant context
For organizations with multiple services requiring different configuration scopes, consider introducing a second dimension in the partition key:

PK = "TENANT#acme-corp|SERVICE#order-service"
SK = "CONFIG#payment-gateway"

This multi-dimensional approach enables service-level isolation where the Order service sees only billing API configurations while the Reporting service doesn’t have access to payment gateway settings. It also provides efficient service-scoped queries, retrieve configurations for a specific service with PK = TENANT#acme-corp|SERVICE#order-service and SK begins with CONFIG#. The second dimension can represent business units, geographic regions, or a logical boundary that aligns with access control requirements, making this pattern particularly valuable when fine-grained access control beyond tenant-level isolation is needed. For detailed guidance on multi-tenant DynamoDB modelling patterns, see amazon-dynamodb-data-modeling-for-multi-tenancy-part-2.

B. Strategy pattern for storage flexibility

The system decides which storage backend to use for each configuration request. The Strategy Pattern is a design approach that allows a program to choose different behaviors at runtime based on context. Think of it like a traffic controller that examines each request and directs it to the appropriate service.

Why use the strategy pattern?

Without the Strategy Pattern, handling multiple storage backends would require complex conditional logic throughout the code base. Different tenant metadata has vastly different access patterns. Routing to optimized backends alleviates both DynamoDB cost explosions (for rarely-changing configs) and Parameter Store throttling (for high-frequency reads), addressing the scaling gap. A naive implementation might look something like this and it’s worth pausing to understand why this approach breaks down.

// Without Strategy Pattern - complex and hard to maintain
async getConfig(key: string, tenantId: string) {
  if (key.startsWith('tenant_config_')) {
    // DynamoDB logic here
    const pk = `TENANT#${tenantId}`;
    const sk = `CONFIG#${key.slice(14)}`;
    return await this.dynamoDB.query({...});
  } else if (key.startsWith('param_config_')) {
    // Parameter Store logic here
    const path = `/config-service/${tenantId}/${key.slice(13)}`;
    return await this.ssm.getParameter({...});
  }
  // More conditions as backends are added...
}

Every time you add a new storage backend, say, AWS Secrets Manager or Amazon S3, you’re forced to reach back into this function and bolt on another else if. The storage logic becomes tightly coupled to your service layer, making it harder to test each backend in isolation and nearly impossible to swap one out without risking regressions elsewhere.

Implementation strategy

The Strategy Pattern encapsulates storage-specific logic into separate, interchangeable strategy classes. This code demonstrates how the factory examines keys and selects strategies:

@Injectable()
export class ConfigStrategyFactory {
  private keyStrategyMap = new Map<string, ConfigStrategy>([
    ['tenant_config_', this.dynamoDBConfigStrategy],
    ['param_config_', this.ssmConfigStrategy],
  ]);
  getStrategy(key: string): ConfigStrategy {
    for (const [prefix, strategy] of this.keyStrategyMap.entries()) {
      if (key.startsWith(prefix)) {
        return strategy;
      }
    }
    throw new ValidationException(`Invalid key format: ${key}`);
  }
}

Key prefix mapping:

  • tenant_config_* → Routes to Amazon DynamoDB for tenant-specific, high-frequency access patterns
  • param_config_* → Routes to AWS Systems Manager Parameter Store for shared, hierarchical parameters

With this approach, adding a new storage backend requires only:

  • Creating a new strategy class implementing the ConfigStrategy interface
  • Adding one line to the keyStrategyMap with the new prefix and strategy
  • No changes to existing strategies or calling code

This design helps protect technology investments. As requirements evolve and new AWS services become relevant, the system adapts without major rewrites.

Multi-layer caching strategy

Different configurations benefit from different caching approaches. The pattern implements different caching strategies optimized for each configuration type’s access patterns and business requirements:

  • High-frequency tenant configurations (accessed thousands of times per minute) use application-level caching with short Time-To-Live (TTL) values. This significantly reduces database queries while maintaining reasonably fresh data.
  • Shared parameters (accessed frequently but change rarely) use in-memory caching with event-driven invalidation. The cache only refreshes when EventBridge detects an actual change, alleviating unnecessary API calls.

Cache Security Considerations

The implementation uses a shared in-memory Map with tenant-prefixed keys (tenantId:serviceName:configKey). Cached values are configuration metadata (API endpoints, feature flags, thresholds), not sensitive data like credentials or PII. Sensitive values remain in Parameter Store with SecureString encryption and are retrieved on-demand, not cached. Even in edge cases, downstream access controls (JWT validation, DynamoDB composite keys) act as the final enforcement boundary.

For teams handling more sensitive configuration payloads, consider Amazon ElastiCache (Redis OSS) or Valkey with key-prefix isolation and encryption at rest/in transit, though this adds 1-3ms network latency versus sub-millisecond in-memory access.

C. Authentication and tenant isolation

Tenant isolation is enforced at multiple layers, starting with JWT-based authentication and custom authorization guards.

Cognito JWT validation flow:

  1. Client authenticates with Cognito and receives JWT token
  2. Request includes JWT in Authorization: Bearer {token} header
  3. CognitoJwtGuard validates token signature against Cognito JSON Web Key Sets (JWKS) endpoint
  4. Guard extracts custom:tenantId claim and attaches to request context
  5. TenantAccessGuard verifies user has access to requested tenant
  6. Service layer uses validated tenantId for data operations

This implementation demonstrates the secure approach to tenant context extraction:

async retrieveConfig(req: RetrieveConfigRequest): Promise<RetrieveConfigResponse> {
  // tenantId is extracted from validated JWT token, never from request parameters
  const tenantId = (req as any).tenantId;
  if (!tenantId) {
    throw new UnauthorizedException('Tenant ID not found in authentication context');
  }
  const strategy = this.strategyFactory.getStrategy(req.key);
  const data = await strategy.getConfig(req.serviceName, req.key, tenantId);
  return { data };
}

Why this approach helps prevent unauthorized access:

Consider what happens if an unauthorized user tries to access another tenant’s configuration:

  1. User authenticates as Tenant A and receives JWT with custom:tenantId: "tenant-a"
  2. User attempts to manipulate request to access Tenant B’s data
  3. The service extracts tenantId from the JWT (still “tenant-a”), ignoring request parameters
  4. Query uses the JWT’s tenant ID, so user only sees Tenant A’s data

Advanced: Infrastructure-level credential isolation

The current design enforces tenant isolation at the application layer through JWT extraction and DynamoDB composite keys. The ECS task uses a shared IAM execution role, meaning tenant requests operate under the same AWS credentials. While this approach is sufficient for most multi-tenant applications, teams with stricter compliance requirements (HIPAA, PCI-DSS, FedRAMP) may need infrastructure-level isolation.

For enhanced isolation, consider implementing a Token Vending Machine (TVM) pattern with AWS Security Token Service (STS) to issue temporary, tenant-scoped IAM credentials. This provides infrastructure-level isolation with per-tenant AWS CloudTrail audit trails and principle of least privilege enforcement. However, TVM adds operational complexity (credential caching, STS API costs, token refresh logic) and latency (50-100ms per operation).

Consider this as a next step when compliance auditors require infrastructure-level separation rather than a baseline requirement.

This design helps prevent cross-tenant access attempts at the infrastructure level, addressing a common security issue.

D. Zero-downtime auto-refresh mechanism

Configuration updates in production systems present a classic operations challenge. This event-driven approach addresses the cache TTL trade-off entirely, configurations update in real-time without polling or staleness windows.

EventBridge integration flow:

1. Parameter Store Change
         ↓
2. EventBridge Rule (matches /config-service/* changes)
         ↓
3. Lambda Function (extracts tenantId from path)
         ↓
4. Service Discovery (AWS Cloud Map queries for healthy instances)
         ↓
5. gRPC Refresh Call (direct service-to-service invocation)
         ↓
6. In-Memory Cache Update (zero-downtime)
         ↓
7. Updated Configuration Active (no connection drops)

Key benefits:

  1. Zero downtime: No service restarts required. Connections remain active
  2. Reactive updates: Only triggers when changes occur (no wasteful polling)
  3. Cost efficient: Minimizes SSM API calls through caching and event-driven refresh
  4. Audit trail: EventBridge provides complete change history and monitoring

When to use this pattern?

The tagged storage pattern isn’t universally applicable. Like most architectural approaches, it has ideal use cases where the benefits significantly outweigh the implementation complexity. Consider this pattern when your application matches these characteristics:

  • Multi-tenant SaaS requiring strict tenant isolation and regulatory compliance benefit significantly. The pattern’s infrastructure-level isolation through JWT claims and data model design provides security commitments that application-level isolation cannot match.
  • Microservices architectures with complex configuration requirements across dozens of services find value in the centralized management and flexible storage routing.
  • Organizations managing configurations across multiple storage backends and environments (dev, staging, production, DR) appreciate the hierarchical organization and path-based access control that Parameter Store provides, combined with DynamoDB’s performance for high-frequency access.
  • High-throughput applications (1000+ requests/second) needing sub-millisecond response times use DynamoDB Accelerator (DAX) for in-memory caching. While DynamoDB offers excellent single-digit millisecond latency, DAX delivers microsecond read latency, typically 5-10x faster for cached data. This makes a substantial difference at scale.
  • Teams prioritizing operational simplicity value the event-driven refresh mechanism that avoids manual deployment coordination.

Getting started

Ready to implement the Tagged Storage Pattern in your organization?

Start with a pilot project focusing on a single microservice and gradually expand the pattern across your architecture. The modular design means that you can realize benefits incrementally while building confidence in the approach.

Implementation steps:

  1. Design your data model: Define DynamoDB schema and Parameter Store hierarchy
  2. Set up Amazon Cognito: Configure user pool with custom tenant attributes
  3. Build the service layer: Implement Strategy Pattern for storage routing
  4. Add event-driven refresh: Configure EventBridge rules and Lambda function
  5. Test tenant isolation: Verify JWT validation and cross-tenant access deterrence
  6. Deploy and monitor: Establish CloudWatch dashboards and operational procedures

You can find the complete code for this solution, including AWS CloudFormation templates, deployment and testing scripts, in the GitHub – Configuration Management Service.

To avoid incurring ongoing charges, delete the resources you created during this walkthrough. For detailed cleanup instructions including step-by-step commands and verification steps, see the Infrastructure Cleanup Guide.

Conclusion

Building a multi-tenant configuration service requires careful consideration of storage patterns, security boundaries, and operational requirements. The tagged storage pattern demonstrated in this post provides a flexible, scalable foundation that addresses these challenges through:

  1. Intelligent storage routing: The Strategy Pattern provides optimal backend selection per configuration type, allowing DynamoDB for tenant-specific settings and SSM Parameter Store for shared parameters.
  2. Zero-downtime updates: Event-driven architecture through EventBridge and Lambda avoids service restarts and polling overhead so that configurations refresh immediately upon changes.
  3. Strong tenant isolation: JWT-based authentication with custom claims makes sure tenant boundaries are enforced at the infrastructure level, not application logic, helping prevent cross-tenant access attempts.
  4. Operational simplicity: In-memory caching, combined with event-driven refresh, can reduce API costs while maintaining microsecond response times.
  5. Cost efficiency: Pay-per-request billing, aggressive caching, and Spot instances help keep operational costs minimal even at scale.

Additional resources


About the authors

A framework for securely collecting forensic artifacts into S3 buckets

Post Syndicated from Jason Garman original https://aws.amazon.com/blogs/security/a-framework-for-securely-collecting-forensic-artifacts-into-s3-buckets/

When customers experience a security incident, they need to acquire forensic artifacts to identify root cause, extract indicators of compromise (IoCs), and validate remediation efforts. NIST 800-86, Guide to Integrating Forensic Techniques into Incident Response, defines digital forensics as a process comprised of four basic phases: collection, examination, analysis, and reporting. This blog post focuses on the first phase—collection—and provides best practices for implementing least privilege during the forensic evidence collection processes that collect evidence and store the artifacts in Amazon Simple Storage Service (Amazon S3) buckets. The architecture presented in this post can be used to collect forensic evidence from both Amazon Web Services (AWS) and non-AWS compute resources.

It’s important to consider the security of the forensic artifact collection process because it involves communicating with potentially compromised resources. The collection methodology itself should be designed to avoid adding additional risks to infrastructure or other forensic investigation processes. At the same time, the collection of forensic artifacts requires the use of specialized tools that are difficult to change or adapt to new security requirements.

This post outlines factors that you should consider when creating an evidence collection capability and introduces an architecture that implements the best practices for least privilege and integrating with (instead of changing or adapting) existing forensic tools that support uploading artifacts to S3 buckets by using AWS security credentials.

Solution architecture

The architecture presented in this post demonstrates the following AWS best practices:

  1. Least privilege – Use AWS Identity and Access Management (IAM) policies to provide least privilege access to upload forensic artifacts to an S3 location dedicated to a specific forensic collection task. The locked down credentials cannot be used to view or modify any other forensic collections.
  2. Time-limited credentials – Use AWS Security Token Service (AWS STS) to provide time limited credentials, reducing the potential for an unauthorized user to abuse credentials while they’re visible on the target machine during the artifact collection process.
  3. Compatibility with third-party tools – Forensic tools are specialized and changing a forensic collection process to adapt to different collection methods might not be possible. To avoid the risk of needing to change tools, maximize compatibility with any third-party tools that support uploading to S3 buckets. The method introduced in this post to generate time-limited, scoped down credentials can be used with most third-party forensic tools that support uploading to S3 buckets.
  4. Credential vending – Use time-limited tokens, which can be vended on demand through an automated process, eliminating the need for forensic investigators to use the AWS Management Console, understand least privilege, or have any access to the AWS control plane. Forensic investigators can focus on the process of collecting and analyzing evidence.
  5. Process automation – Deploy the process as infrastructure as code (IaC) and automate it through AWS services, reducing the burden on security teams to manually perform runbook steps during an active security incident.

This post starts with an overview of the digital forensic process, provides best practices for using Amazon S3 to store forensic artifacts, details how you can create time-limited, least privilege tokens to provide secure access to upload forensic artifacts to S3 buckets, and introduces a sample architecture that automates the end-to-end process.

The digital forensic process

Organizations need to have practices and resources in place to support a digital forensic investigation environment before an incident occurs. AWS has published several resources, including Forensic investigation environment strategies in the AWS Cloud and AWS prescriptive guidance: Security Reference Architecture, Cyber forensics, to provide best practices for organizing your AWS accounts using AWS Organizations to support forensic clean-room environments. Creating segregated AWS accounts and resources for your security teams is critical to provide your incident responders a location to store and analyze any digital forensic evidence collected during an investigation.

After you’ve established a landing zone for performing digital forensics, you’re ready to collect and process digital forensic evidence. AWS supports the collection of digital forensics through extensive logging of control plane events in AWS CloudTrail, and metrics and application logs that can be stored in Amazon CloudWatch. In addition, AWS core compute services, such as Amazon Elastic Compute Cloud (Amazon EC2), support forensics operations through snapshots of the underlying Amazon Elastic Block Storage (Amazon EBS) volume. An example architecture to demonstrate how to automate the collection of EBS volume snapshots for forensic investigations can be found in How to automate forensic disk collection in AWS.

You might want to use the same AWS infrastructure to collect, examine, analyze, and report on forensic incidents that occur on other resources, such as corporate laptops. You can use existing forensic tooling to perform live response, collecting specific artifacts such as Windows NT File System (NTFS) Master File Table (MFT), logs from Linux machines, volatile memory images, or other artifacts that are specified as part of your organization’s incident response plan. These tools can be provided by third parties or built in-house, and many support uploading to S3 buckets using AWS security credentials.

Using Amazon S3 for forensic artifact collection

Amazon S3 provides the foundational requirements for collecting and storing forensic artifacts. Digital forensics requires highly available, durable, and secure storage of artifacts collected from potentially compromised systems. Amazon S3 is designed for 11 nines of durability and can be configured to provide protection against modification, deletion, and unauthorized access to sensitive forensic artifacts. You can also use S3 to store forensic artifacts of almost any size—from one byte to 5 TB—in an S3 object.

S3 buckets used to store forensic artifacts require custom configuration to provide additional security. You should configure the S3 bucket that you use to store forensic artifacts to enable the following security and governance features:

  1. Encryption in transit. You can require the use of encryption in transit and specify acceptable TLS versions using the aws:SecureTransport and s3:TlsVersion condition keys on the S3 bucket policy.
  2. Encryption at rest using a customer managed key. You can automatically encrypt all objects uploaded to the bucket using a specified customer managed key by specifying a default server-side encryption key in the bucket’s configuration. For this post, we encourage you to use a customer managed key rather than relying upon an AWS managed key, so you can control the associated key policy.
    1. Encryption at rest provides an additional layer of protection, because only entities that have both the permission to read from the bucket and permission to use the AWS Key Management Service (AWS KMS) key for decryption can download the forensic artifact from the S3 bucket.
    2. You need to adjust the example KMS policies in this post if the evidence collection S3 bucket uses the S3 Bucket Key feature.
  3. Audit logs of all S3 data event activity. You can turn on CloudTrail data events for any S3 buckets that contain forensic artifacts to provide a comprehensive audit trail of S3 object-level API activity. This helps provide a chain of custody of any artifacts stored in your forensic buckets.
  4. Fine-grained access control using IAM permissions. You can define the set of entities (both human and machine) that have access to the artifacts in the S3 bucket. This post includes how to create time-limited, least privilege access using IAM permissions for uploading files into an S3 bucket. The permissions are fine-grained enough to scope down access to specific object names or object prefixes in an S3 bucket. Additionally, access to read the artifacts can be controlled through IAM permissions and access to the encryption-at-rest KMS key.
  5. Protections against data modification and deletion. S3 provides features, such as S3 object versioning, to provide assurances that data hasn’t been modified or removed after it’s been collected. This is an additional layer of protection beyond the fine-grained access permissions, so even if an authorized entity attempts to overwrite or delete an object in the S3 bucket, the previous version of the object is still available.
  6. There are additional options that you can configure on the S3 bucket to protect your data against modification and deletion, including S3 Object Lock and multi-factor authentication (MFA) delete.

In addition to the preceding configuration, consider how to organize forensic artifacts in the S3 bucket. This post introduces a folder structure using S3 object prefixes to segregate each forensic artifact collection task into its own S3 object namespace. An example S3 namespace structure for an S3 bucket is shown in Figure 1.

Figure 1 – S3 namespace structure for an S3 forensics artifact bucket using object prefixes

Figure 1: S3 namespace structure for an S3 forensics artifact bucket using object prefixes

By separating each forensic collection task by its own prefix, you can use fine-grained IAM permissions to permit object uploads only into the active collection task. For example, scoped down credentials can be generated to only allow uploads into buckets with the CASE-0001 prefix using an IAM permission as shown in the following code example. Temporary security credentials can be generated using these limited permissions and the key is then used by the forensic acquisition tool to upload the artifacts into the S3 bucket.

{
	"Sid": "UploadToCase0001",
	"Effect": "Allow",
	"Action": [
		"s3:PutObject",
		"s3:AbortMultipartUpload"
	],
"	Resource": "arn:aws:s3:::mycompany-forensics-collection/CASE-0001/*"
}

Manually creating temporary IAM credentials for each forensic collection activity can be error-prone and time-consuming. Therefore, this post demonstrates how to use AWS tooling to automate the process of generating time-limited, scoped-down credentials.

Adapt existing forensic tools for AWS best security practices

Existing forensic tools typically use IAM access keys to perform S3 operations. Using a static IAM user secret access key isn’t a best practice. Even if the static key is associated with an IAM user that has been scoped down to only have access to the forensic collection S3 bucket as described previously, that means anyone with access to that key can potentially upload objects into that bucket. Therefore, the best practice is to create a time-limited temporary security credential unique to each collection activity, scoped down to only allow uploading files to a specific prefix in the target S3 bucket.

The examples in this post use the following resource names. Because these names will change based on your deployment, substitute your resource names in place of the names in the example code.

  1. The evidence S3 bucket is named mycompany-forensics-collection
  2. The forensics AWS account number is 112233445566. For the purposes of this example, all resources will live within this account.
  3. The customer managed key used to encrypt the forensic artifacts at rest is ForensicsEvidenceKey
  4. The IAM role that incident responders will assume when signing in to their AWS account is ForensicsUserRole
  5. The IAM role that incident responders will use for generating S3 file upload temporary credentials is ForensicsUploadRole
  6. The example uses the us-east-1 AWS Region

The following steps show you how to configure the IAM policies associated with the customer managed key ForensicsEvidenceKey and the IAM role ForensicsUploadRole.
Before you begin, create the evidence S3 bucket configured as described in Using S3 for artifact collection and a customer managed key to encrypt the forensic artifacts at rest. Configure the evidence S3 bucket to use the KMS key by opening the S3 bucket’s properties tab in the Amazon S3 console and setting the new KMS key as the default encryption key for the bucket.

Next, create an IAM role that incident responders will assume through the AWS STS AssumeRole API to generate the temporary credentials. This role will define the maximum set of permissions allowed to upload artifacts to your evidence S3 bucket. This role, ForensicsUploadRole, created using the following example code, defines the maximum allowable permissions: the ability to upload objects into the evidence S3 bucket and to use the KMS key to encrypt those uploads. The effective permissions available to the forensic tool will be scoped down even further to the specific object prefix when the AWS STS temporary security credential is generated.

Note that the policy allows the forensics upload role Decrypt permission in addition to Encrypt; this is required when uploading files larger than 5 GB using the multi-part S3 file upload feature.

{
	"Version": "2012-10-17",
	"Statement": [
			{
				"Sid": "BasePermissionsForS3Upload",
				"Effect": "Allow",
				"Action": [
					"s3:PutObject",
					"s3:AbortMultipartUpload"
				],
				"Resource": "arn:aws:s3:::mycompany-forensics-collection/*"
		},
		{
			"Sid": "KeyAccessToS3Upload",
			"Effect": "Allow",
			"Action": [
				"kms:GenerateDataKey",
				"kms:Encrypt",
				"kms:Decrypt"
			],
			"Resource": "arn:aws:kms:us-east-1:112233445566:alias/ForensicsEvidenceKey",
			"Condition": {
				"StringLike": {
					"kms:EncryptionContext:aws:s3:arn": "arn:aws:s3:::mycompany-forensics-collection/*"
				}
			}
		}
	]
}

Next, you need to provide an ability to assume this role and generate AWS STS tokens using the role’s permissions. This is accomplished by creating a trust relationship associated with the IAM role you just created. The trust relationship shown in the following code sample describes which AWS principals are allowed to assume the role—in this case, you will allow any user who has federated into the ForensicsUserRole IAM role to be able to generate AWS STS tokens for forensic artifact collection.

{
	"Version": "2012-10-17",
	"Statement": [
		{
			"Sid": "Statement1",
			"Effect": "Allow",
			"Principal": {
				"AWS": "arn:aws:iam::112233445566:role/ForensicsUserRole"
			},
			"Action": "sts:AssumeRole"
		}
	]
}

After the role is established and access to the encryption key is granted, you can use the AWS STS AssumeRole API to create temporary credentials using this role. You can call this API using the AWS Command Line Interface (AWS CLI) or programmatically from a script. To scope down the token’s access to only provide permission to upload to the specific evidence object prefix, you must include a session policy as part of your AssumeRole API request to AWS STS. The following is an example session policy to restrict access to only upload objects into the CASE-0001 prefix.

[
	{
		"Effect": "Allow",
		"Action": [
			"s3:PutObject", 
			"s3:AbortMultipartUpload"
		],
		"Resource": "arn:aws:s3:::mycompany-forensics-collection/CASE-0001/*"
	},
	{
		"Effect": "Allow",
		"Action": [
			"kms:GenerateDataKey", 
			"kms:Encrypt", 
			"kms:Decrypt"
		],
		"Resource": "*",
		"Condition": {
			"StringLike": {
				"kms:EncryptionContext:aws:s3:arn": "arn:aws:s3:::mycompany-forensics-collection/CASE-0001/*"
			}
		}
	}
]

The effective permissions available to the session role will be the intersection of permissions available in the role policy (ForensicsUploadRole), the resource policy (in this case, mandating TLS-encrypted connections to the bucket), and the session policy that’s created on demand for every forensic collection (only allowing access to upload objects into the CASE-0001 prefix, as shown in the preceding example). Pictorially, this looks like the Venn diagram shown in Figure 2.

Figure 2 – Intersection of IAM policies determine the effective permissions for the restricted forensic session role.

Figure 2: Intersection of IAM policies determine the effective permissions for the restricted forensic session role.

Test the temporary credentials

Now that the bucket has been created and the AWS KMS key and roles configured, you can use AWS STS to create a temporary security credential for a collection on CASE-0001. You can use the AWS CLI to do this manually or you can write a script to automate this process using the AWS API. The IAM access key, secret access key, and session token returned by this call can then be used by any tool that can use AWS access keys to upload files into the specified S3 bucket.

The following example shows an AWS CLI call to AssumeRole using the example ForensicsUploadRole and a case named CASE-0001. The --duration-seconds parameter defines the period, in seconds, that the temporary credentials are valid; the default of 3600 seconds will provide temporary credentials that are valid for one hour.

$ aws sts assume-role \
	--role-arn arn:aws:iam::112233445566:role/ForensicsUploadRole \
	--role-session-name CASE-0001 \
	--duration-seconds 3600 \
	--policy '{"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Action": ["s3:PutObject", "s3:AbortMultipartUpload"], "Resource": "arn:aws:s3:::mycompany-forensics-collection/CASE-0001/*"}, {"Sid": "BasePermissionsForS3Upload", "Effect": "Allow", "Action": ["kms:GenerateDataKey", "kms:Encrypt", "kms:Decrypt"], "Resource": "*"}]}'

{
	"Credentials": {
		"AccessKeyId": "ASIAXXXX",
		"SecretAccessKey": "XXXX",
		"SessionToken": "XXXX",
		"Expiration": "2025-04-10T17:16:13+00:00"
	},
	"AssumedRoleUser": {
		"AssumedRoleId": "AROXXXX:CASE-0001",
		"Arn": "arn:aws:sts::112233445566:assumed-role/ForensicsUploadRole/CASE-0001"
	},
	"PackedPolicySize": 39
}

Now that you have obtained temporary credentials from AWS STS, you can use those credentials to upload a file into Amazon S3:

$ AWS_ACCESS_KEY_ID=ASIAXXXX \
	AWS_SECRET_ACCESS_KEY=XXXX \
	AWS_SESSION_TOKEN=XXXX \
	aws s3 cp evidence.zip s3://mycompany-forensics-collection/CASE-0001/evidence.zip

upload: evidence.zip to s3://mycompany-forensics-collection/CASE-0001/evidence.zip

You can also verify that you can’t use those credentials to upload a file into any other object prefixes or S3 buckets. For example, if you change CASE-0001 to CASE-0004 in the Amazon S3 upload command, you will receive an AccessDenied error because you’re trying to upload an object outside of the allowed key prefix.

$ AWS_ACCESS_KEY_ID=ASIAXXXX \
	AWS_SECRET_ACCESS_KEY=XXXX \
	AWS_SESSION_TOKEN=XXXX \
	aws s3 cp evidence.zip s3://mycompany-forensics-collection/CASE-0004/evidence.zip

upload failed: evidence.zip to s3://mycompany-forensics-collection/cases/CASE-0004/evidence.zip
An error occurred (AccessDenied) when calling the PutObject operation: User: arn:aws:sts::112233445566:assumed-role/ForensicsUploadRole/CASE-0001 is not authorized to perform: s3:PutObject on resource: "arn:aws:s3:::mycompany-forensics-collection/CASE-0004/evidence.zip" because no session policy allows the s3:PutObject action

Additionally, if you wait more than the lifetime of the token (1 hour in this case), attempting to upload a file into the bucket will fail, because the token will no longer be valid:

$ AWS_ACCESS_KEY_ID=ASIAXXXX \
	AWS_SECRET_ACCESS_KEY=XXXX \
	AWS_SESSION_TOKEN=XXXX \
	aws s3 cp evidence.zip s3://mycompany-forensics-collection/CASE-0001/evidence.zip

upload failed: evidence.zip to s3://mycompany-forensics-collection/CASE-0001/evidence.zip

An error occurred (ExpiredToken) when calling the PutObject operation: The provided token has expired.

Create an automated process to vend temporary credentials on demand

After you’ve verified the security benefits of creating temporary credentials for S3 uploads and validated that the credentials work with your forensic software of choice, you can now use them as part of an automated process.

A sample automated architecture is shown in Figure 3.

Figure 3: Architecture to automate S3 credential vending and forensic artifact collection.

Figure 3: Architecture to automate S3 credential vending and forensic artifact collection.

The workflow depicted in Figure 3 includes the following steps:

  1. The workflow is triggered by an alert from a detection source or a manual trigger from an incident responder.
  2. The workflow input is added to an Amazon Simple Queue Service (Amazon SQS) queue.
  3. The Amazon SQS queue invokes an AWS Lambda function which in turn executes a Step Functions state machine to orchestrate the workflow.
  4. First, the Step Functions workflow determines whether the target system is managed by AWS Systems Manager.
    1. If the target system isn’t managed by Systems Manager, an error is noted, and the execution is abandoned.
    2. If the target system is managed by Systems Manager, the Step Functions workflow determines the operating system (OS) of the target system and proceeds with the flow of execution.
  5. The workflow then continues by executing the Systems Manager documents that implement the forensic collection process:
    1. Downloads tooling:
      1. Generates dynamically scoped IAM temporary credentials that provide access to download the OS-specific tooling to be executed on the target system from the tooling S3 bucket. These credentials are tightly scoped to only allow downloads from the S3 prefix that corresponds to the tooling for the target system’s OS.
      2. Executes a Systems Manager command on the target system that uses the credentials generated from the previous step to download the OS tooling on the target system.
    2. Runs forensic tools:
      • Executes a Systems Manager command on the target system to execute the OS tooling on the target system.
  6. The Systems Manager commands run on the target system, which in this case is an EC2 instance.
  7. Results are uploaded to the evidence S3 bucket:
    1. Generates dynamically scoped IAM temporary credentials (as described previously) that provide access to upload the output of the previously executed tooling to the evidence S3 bucket. These credentials are tightly scoped to only allow uploads to a particular S3 prefix corresponding to the alert prefix.
    2. Executes a Systems Manager command on the target system to upload the output of the previously executed tooling to the evidence S3 bucket. After the upload is complete, it cleans up both the output and the evidence tooling from the target system.
    3. The evidence S3 bucket is tightly locked down to a subset of identities within the AWS security account. Access attempts from identities that aren’t allow listed trigger an Amazon EventBridge rule to alert the security team through an Amazon Simple Notification Service (Amazon SNS) topic.
  8. When the workflow is complete, related details and metrics are recorded in an Amazon DynamoDB table.
  9. The forensic analysis can be performed on a separate EC2 instance that has access to read from the evidence S3 bucket.

Deploying the example solution

You can use the AWS Cloud Development Kit (AWS CDK) repository to implement the architecture shown in Figure 3.

The AWS CDK solution is split into three stacks:

  1. SecurityStack: This stack contains the basic forensic artifact workflow orchestration infrastructure described in this post, including the Step Functions workflow, Lambda functions, AWS SQS queues, IAM roles, and S3 buckets.
  2. AlertStack: This stack contains the EventBridge workflow to notify administrators of anomalous activity in the evidence S3 bucket.
  3. CustomerStack: This stack contains the SSM documents that are executed for the forensic artifact workflow and an IAM role assumed by the SecurityStack when the workflow is invoked. It’s deployed into each child AWS account containing EC2 instances from which the security account is authorized to collect forensic artifacts.

Configuration

Before deploying the solution, there are several variables in the config.ts file that must be modified for the environment:

  1. SECURITY_ACCOUNT: Security Tooling AWS account ID.
  2. CUSTOMER_ACCOUNTS: Target AWS account IDs (the Child AWS account in the architecture diagram).
  3. ALERT_EMAIL_RECIPIENTS: List of email addresses that receive alerts when there is unexpected access to the evidence S3 bucket.
  4. ALLOW_LISTED_ROLE_NAMES: Roles allowed to access the evidence S3 bucket. Any other identities accessing the evidence S3 bucket will result in an alarm.

Deployment

After you’ve updated the config.ts file to reflect the account numbers, email recipients, and role names, the stacks can be deployed into your AWS infrastructure.

  1. Set Up AWS credentials using the AWS CLI:
    aws configure
  2. Install dependencies and configure constants:
    1. Clone the repository.
    2. Navigate to the project directory.
    3. Install project dependencies:
      npm install
    4. Configure constants in constants/config.ts with the required information:
      export const SECURITY_ACCOUNT = "123456789012"; // Your security tooling account ID 
      export const CUSTOMER_ACCOUNTS = ["234567890123", "345678901234"]; // Target account IDs 
      export const ALLOW_LISTED_ROLE_NAMES = ["SecurityAnalystRole"];// Roles allowed to access evidence S3 bucket 
      export const ALERT_EMAIL_RECIPIENTS = ["[email protected]"];// Email addresses for alerts

  3. Bootstrap AWS CDK in your accounts (if it hasn’t been done already):
    1. Example: cdk bootstrap aws://456789012345/us-east-1 (example security AWS account).
    2. Then bootstrap if necessary in any target AWS accounts.
  4. Deploy the AWS CDK Stacks:
    1. Synthesize the CloudFormation template:
      cdk synth
    2. Deploy the security and alert stacks in your security account:
      cdk deploy SecurityStack AlertStack
    3. Deploy the customer stacks in your workload accounts:
      cdk deploy CustomerStack-ACCOUNT_ID
  5. Set up your email alerts:
    1. After the AlertStack is deployed, it will email all addresses listed in ALERT_EMAIL_RECIPIENTS. Choose the embedded link to accept the AWS SNS topic in each of those accounts.

Testing

With deployment complete, it’s time to test the solution.

  1. Trigger an analysis
    1. Make sure you have a Linux EC2 instance running in one of your customer accounts and in the AWS Region where you deployed the preceding customer stack.
    2. Because this example uses Systems Manager to orchestrate the collection script, make sure that the EC2 instance is visible in Systems Manager either by checking the Systems Manager console, or by using the AWS CLI:
      1. Console: In the AWS Systems Manager console, choose Managed instances in the left navigation pane and verify your instance appears in the list. For more information, see Managed Instances in the AWS Systems Manager User Guide.
      2. AWS CLI: Run the following command to verify the instance is managed:
        aws ssm describe-instance-information --filters “Key=InstanceIds,Values=<instance-id>
        If the command returns instance information with PingStatus: Online, the instance is properly connected to Systems Manager.
    3. Post a message in your security account to the Amazon SQS queue to start the Step Functions workflow. Note that the values in angle brackets (for example <accountID>) are placeholders that you must update with relevant AWS account ID, tracking ticket ID, AWS Region, and EC2 instance ID values:
      aws sqs send-message --queue-url --message-body ‘{ “account”: “”, “ticket_id”: “”, “region”: “>”, “instance_id”: “” }’
  2. Go to the Step Functions console to view the successful execution of the workflow:
    Figure 4 – Workflow as shown in the Step Functions console

    Figure 4: Workflow as shown in the Step Functions console

  3. View the DynamoDB table to see the metadata for the results.
  4. Check the evidence S3 bucket to see the uploaded files from the forensic collection.

Conclusion

Collecting forensic artifacts securely is a critical component of any digital forensics investigation. This post demonstrated how to implement least privilege access controls and time-limited credentials for forensic evidence collection workflows that use Amazon S3 for artifact storage. By combining IAM session policies with AWS STS temporary credentials, you can provide forensic tools with secure, scoped-down access to upload artifacts without exposing long-lived credentials or granting overly permissive access.

The architecture presented in this post automates the process of generating temporary credentials, collecting forensic artifacts from both AWS and non-AWS resources, and securely storing them in S3 buckets with appropriate encryption, access controls, and audit logging. With this approach, your security teams can focus on analyzing evidence instead of managing credentials and permissions during active security incidents.To get started with this solution, deploy the example AWS CDK stacks provided in the collect forensic artifacts repository and customize them for your organization’s forensic investigation requirements. For more information about related AWS forensic investigation architectures, review the Automated Forensics Orchestrator for EC2 and How to build forensic kernel modules for Linux EC2 instances resources.

If you have feedback about this post, submit comments in the Comments section below. If you have questions about this post, contact AWS Support.

Jason Garman

Jason Garman

Jason is a principal security specialist solutions architect at AWS. He has 30 years of cybersecurity experience including incident response, reverse engineering, identity, and data protection. At AWS, he helps large organizations adopt the latest cloud and AI technologies while maintaining a high bar for data governance, security, and safety.

Vaishnav Murthy

Vaishnav Murthy

Vaishnav is a Senior Security Engineer with AWS CloudResponse. He has an extensive background in incident response and security automation and enjoys building automated solutions that help AWS customers investigate and respond to security incidents at scale.

[$] Ripping CDs and converting audio with fre:ac

Post Syndicated from jzb original https://lwn.net/Articles/1062141/

It has been a little while since LWN last surveyed tools for managing a digital
music collection
. In the intervening decades, many Linux users have moved on to
music streaming services, found them wanting, and are looking to curate their own
collection once again. There are plenty of choices when it comes to
ripping, managing, and playing digital audio; so many, in fact, that it can be a
bit daunting. After years of tinkering, I’ve found a few tools that work well for
managing my digital library: the first I’d like to cover is the fre:ac free audio encoder for ripping music from
CDs and converting between audio formats.

[$] An API for handling arithmetic overflow

Post Syndicated from daroc original https://lwn.net/Articles/1065889/

On March 31, Kees Cook shared

a patch set
that represents the culmination of more than a year of work
toward eliminating the possibility of silent, unintentional integer overflow in
the kernel. Linus Torvalds was

not pleased
with the approach, leading to a detailed discussion about the
meaning of “safe” integer operations and the design of APIs for handling integer
overflows. Eventually, the developers involved reached a consensus for a
different API that should make handling overflow errors in the kernel much less
of a hassle.

Nix privilege escalation security advisory

Post Syndicated from jzb original https://lwn.net/Articles/1066813/

The NixOS project has announced
a critical vulnerability
in many versions of the Nix package
manager’s daemon. The flaw was introduced as part of a fix for a
prior vulnerability in 2024
. According to the advisory,
all default configurations of NixOS and systems building untrusted derivations
are impacted.

A bug in the fix for CVE-2024-27297
allowed for arbitrary overwrites of files writable by the Nix process
orchestrating the builds (typically the Nix daemon running as root in
multi-user installations) by following symlinks during fixed-output
derivation output registration. This affects sandboxed Linux builds –
sandboxed macOS builds are unaffected. The location of the temporary
output used for the output copy was located inside the build chroot. A
symlink, pointing to an arbitrary location in the filesystem, could be
created by the derivation builder at that path. During output
registration, the Nix process (running in the host mount namespace)
would follow that symlink and overwrite the destination with the
derivation’s output contents.

In multi-user installations, this allows all users able to submit
builds to the Nix daemon (allowed-users – defaulting to all users) to
gain root privileges by modifying sensitive files.

FortiGate CVE-2025-59718 Exploitation: Incident Response Findings

Post Syndicated from Eric Carey original https://www.rapid7.com/blog/post/ve-fortigate-cve-2025-59718-exploitation-incident-response-ir-findings

Rapid7’s Incident Response (IR) team was engaged to investigate an incident involving exploitation of CVE-2025-59718 against a vulnerable FortiGate appliance. In December 2025, Fortinet disclosed this improper verification of cryptographic signature vulnerability that facilitates an SSO login bypass on affected appliances. After the initial exploitation, the attackers maintained a low-profile posture, systematically compromising additional firewalls before moving to internal network hosts. Ultimately, this grace period allowed responders to contain the threat before further impact could occur within the environment. This blog details exploitation insights, attack progression, and practical detection opportunities for defenders handling their own environments.

Investigative methodology: Tracing the initial access vector in FortiGate appliances

Identifying the Initial Access Vector (IAV) is a cornerstone of any incident response engagement. However, when the source of compromise is not immediately obvious, particularly when edge device exploitation is involved, responders often need to take a broader investigative approach. Rather than starting with a clear point of entry, investigators must analyze the available telemetry, reconstruct attacker activity, and work backwards to determine how access was first obtained.

This process often involves multiple investigative workstreams running in parallel, each designed to answer different questions about the intrusion. As many IR responders and enthusiasts know, the first suspicious event observed during an investigation is rarely the first action taken by the attacker. Instead, it typically represents a point somewhere in the middle of a larger attack chain.

A key step in incident response investigations is reconstructing the attacker timeline. Responders often take an “inside out” approach where they move outward from the initial alert to the full scope of the malicious activity (IAV), correlating multiple data sources to map the unfolding of the event. This process involves examining authentication logs, endpoint telemetry, firewall events, and records of system changes, rather than depending on just one log source. It also typically requires frequent pivoting between artifacts as investigations rarely ever unfold in a linear fashion. By aligning these findings and events chronologically, investigators often identify activity that predates the initial alert.

CVE-2025-59718: Technical analysis and observed attacker behavior

The first activity that drew attention was enumeration and credential discovery within the internal environment. This basic enumeration included gathering information about users, systems, and accessible resources within common user directories. This activity eventually expanded to SMB-based file scraping and network share access, allowing attackers to review files stored across the environment. While this behavior resembled routine administration, the chronological sequence of file scraping and network share access painted a clear picture of an attacker’s initial discovery phase.

Digging deeper into the credential discovery activity, the popular tool Mimikatz was utilized to harvest credentials from various sources within the impacted environment. The attacker’s objective was to obtain valid credentials to an elevated admin account with the goal to blend in.

With credentials in hand and mimicking admin activity to disguise their actions, the attacker was then enabled to move laterally throughout the environment using common administrative tools and access methods. PsExec and Microsoft Remote Desktop (RDP) were two tools utilized for lateral movement while standard web browsers facilitated application access.

Attackers appeared particularly interested in systems that could provide broader access to the environment, including virtualization platforms, domain controllers, and servers supporting backup infrastructure. These systems often represent high-value targets for attackers seeking to escalate privileges, access sensitive data, or disrupt recovery capabilities.

Responders were working simultaneously to contain the attacker while building the narrative to cut them off at the source. With the current understanding of the narrative, the IAV puzzle began to unravel as more information came to light. Strangely, the first authentication into the Windows environment originated from an internal IP address that did not align with the known internal IP address ranges. It turns out, this internal IP address fell within the DHCP lease range of the FortiGate device. At first glance, this could be written off as legitimate VPN activity. However, to create even more questions, it was revealed that the FortiGate SSL VPN was never turned on within this environment. This revelation made the FortiGate device a prime suspect for IAV.

Taking a closer look at the FortiGate device, specifically system logs and configuration data, revealed early indications that the device had been modified to support continued access. The SSL VPN component had been enabled, and multiple configuration changes were identified, including edits to VPN settings, the creation of new firewall policies, and adjustments to configuration parameters. These changes appeared in FortiGate system logs as configuration updates similar to the following:

logid="0100044546" type="event" subtype="system" level="information"
vd="root" logdesc="Attribute configured" user="admins"
ui="GUI(45.32.216[.]250)" action="Edit" cfgpath="vpn.ssl.settings"
msg="Edit vpn.ssl.settings"

⠀

logid="0100044547" type="event" subtype="system" level="information" 
vd="root" logdesc="Object attribute configured" user="admins" 
ui="GUI(45.32.216[.]250)" action="Add" cfgpath="firewall.policy" 
cfgobj="XX" msg="Add firewall.policy <redacted>"

⠀

While these types of changes may seem routine in isolation, it is the combination and timing of these actions that raises concerns from a responder’s perspective. The investigation’s next key clue was identified when the source of these changes was traced back to a newly created account.

Following this thread further, investigators identified that multiple accounts had been created on the device, including SSO administrator, system administrator, and local accounts. Several of these accounts were associated with email domains attributed to Namecheap-hosted infrastructure, including domains such as openmail[.]pro. Notably, some of the newly created SSO administrator accounts were linked to forticloud.com domains as reflected in log entries such as:

Object attribute configured(Add system.sso-forticloud-admin <attacker account>@forticloud.com-1)

⠀

For responders, the creation of multiple new administrative accounts is often a strong indicator of persistence being established. Continuing to work backwards through the timeline, investigators identified that prior to these account creation events, the device’s configuration file was downloaded through the FortiGate UI. From an investigative perspective, configuration exports are highly valuable to attackers because they effectively serve as a blueprint of the environment, exposing network architecture, authentication mechanisms/settings, device relationships, and occasionally, sensitive credentials.

logid="0100032095" type="event" subtype="system" level="warning" 
vd="root" logdesc="Admin performed an action from GUI" user="admin" 
ui="GUI(104.28.227[.]105)" action="download" status="success" 
msg="System config file has been downloaded by user admin via GUI(104.28.227[.]105)"

⠀

The session associated with the configuration download was established from an external IP address flagged as “malicious” by security vendors with a local account already present on the device. All of these new findings from the attacker’s actions can now be utilized as IOCs to scope available FortiGate logs to determine any other leads.

By correlating activity with the known malicious IP addresses, investigators identified the true entry point: administrative SSO logins to the FortiGate appliance with valid accounts. Another important detail was that there was no evidence of brute-forcing activity for these local accounts. The initial access was established approximately two weeks before any subsequent malicious activity, indicating the attacker used this time to secure consistent access to the environment via the FortiGate device.

Actions such as changing configurations, creating accounts, and downloading configurations might seem harmless individually. However, when viewed together, these activities established a clear pattern consistent with the exploitation of CVE-2025-59718 that facilitated authentication bypass.

Once this groundwork was established through persistence mechanisms and discovery, attackers began authenticating into the environment with their newly created accounts via the SSL VPN connections that led us to investigate the FortiGate device in the first place. These sessions effectively transformed the firewall into an ingress point into the internal network, allowing attackers to move beyond the edge device.

This investigation highlights a common reality in incident response where the first indicator of suspicious activity is rarely the beginning of the story. Instead, responders are often working from a point somewhere in the middle, tasked with reconstructing attacker behavior and peeling back layers of activity to uncover how access was first obtained. 

By following the digital breadcrumbs left behind within available evidence sources, investigators were able to trace the intrusion back to its origin. This process emphasizes the importance of working backward through artifacts and telemetry, recognizing that each piece of data may lead to an earlier stage of attacker activity.

Network edge devices such as firewalls and VPN appliances are often the main vectors of initial access. Despite being critical infrastructure in modern environments, full visibility is rarely achieved in comparison to monitored endpoints. These edge devices can provide valuable evidence during investigations and reveal how initial access went unnoticed.

Conclusion: Key takeaways for defenders

The human element of investigation is crucial. Effective investigations demand a mindset of curiosity; on one side the willingness to dig deeper, and on the other, the ability to look at the big picture. At face value these can seem contradictory, but each facilitates a specific role within an incident response investigation.

Curiosity is what drives responders to grapple with the initial evidence, question assumptions, and identify which threads are worth pulling. It allows responders to move beyond surface-level observations and begin forming hypotheses about what may have occurred. The willingness to dive deeper is what turns those hypotheses into answers. Rather than stopping at the first suspicious event, responders must continue pivoting across logs, correlating activity, and tracing actions further back in time. At the same time, maintaining a big-picture perspective is critical. Individual artifacts or events may appear benign in isolation but when viewed chronologically the attacker behavior emerges.

Looking past any specific incident response methodology, visibility into the environment is essential. Even the strongest investigative approach is limited without access to the right telemetry, thus preventing responders from fully reconstructing an intrusion. In particular, as seen within this investigation, visibility into edge device activity can play a crucial role in unraveling IAV. The network edge is a hostile environment yet is frequently less monitored.

As is often the case with externally facing services and devices, the network edge is constantly targeted. Due to the sheer volume of persistent targeting, this environment can prove difficult to monitor for successful malicious intrusions. Implementing centralized syslog monitoring across these edge devices can close these visibility gaps. It can provide a real-time audit trail of connection attempts, configuration changes, and potential exploit signatures that occur before a threat reaches the internal network.

By effectively pulling on each investigative thread and ensuring visibility across both internal systems and edge devices, defenders can uncover compromises that might otherwise remain hidden. Often, the path to the beginning of the intrusion is already present; it simply requires knowing where, and how, to look.

Detection coverage for Rapid7 customers

Rapid7 actively monitors for emerging threats and leverages evidence from incident response engagements to develop new detection capabilities. Detections have been created and implemented by Rapid7 to pinpoint both exploitation attempts and post-exploitation activities related to FortiGate CVE-2025-59718. For InsightIDR and MDR customers, these detections alert on attacker activity consistent with the techniques described in this blog, enabling earlier identification and response before an intrusion can escalate further.

Detections:

  • Potential Exploitation – FortiGate Admin SSO Login and Config Download via External IP

  • Exfiltration – FortiGate Config Downloaded Using GUI via External IP

  • Suspicious Authentication – FortiGate SSO Login via External IP

Mitigation guidance

Please refer to our initial blog from December, 2025.

MITRE ATT&CK Techniques

Tactic

Technique

Details

Initial Access

Exploit Public-Facing Application (T1190)

Exploitation of vulnerability CVE-2025-59718 on FortiGate firewalls.

Persistence

Create Account (T1136)

Creation of local accounts on FortiGate firewalls.

Persistence and Initial Access

Valid Accounts (T1078)

Use of created accounts and compromised accounts for SSL VPN and RDP authentication.

Defense Evasion

Impair Defenses (T1562)

Firewall rules added to allow for attacker access.

Credential Access

OS Credential Dumping (T1003)

Execution of Mimikatz targeting the local system and Windows Registry hives containing credentials.

Discovery

System Network Configuration Discovery (T1016)

Download of FortiGate firewall configuration files containing sensitive networking information.

Discovery

Network Service Scanning (T1046)

Execution of network scanning tools such as Advanced_Port_Scanner to scan internal IP addresses over SMB protocol.

Lateral Movement

Remote Services (T1021)

Use of Remote Desktop Protocol (RDP).

Execution

Service Execution (T1569.002)

Remote execution of the sysinternals tool PsExec to test credentials against an impacted system.

Indicators of compromise (IOCs)

IOC

Description

Advanced_IP_Scanner_2.5.4594.1.exe

Advanced IP Scanner tool utilized by the attacker.

advanced_ip_scanner.exe 

Advanced IP Scanner tool utilized by the attacker.

mimikatz.exe

An open-source post-exploitation tool utilized by the attacker to extract sensitive authentication credentials.

Advanced_port_scanner_2.5.3869.exe

An open-source network utility utilized by the attacker to quickly map active devices and identify open ports.

23.163.8[.]21

Attacker IP address that targeted FortiGate device.

45.32.216[.]250

IP address used by the attacker during FortiGate configuration changes.

45.84.107[.]17

IP address identified in malicious interaction with SSLVPN.

45.80.186[.]84

IP address identified in malicious interaction with SSLVPN.

185.219.157[.]127

IP address identified in malicious interaction with SSLVPN.

185.175.59[.]238

IP address identified in malicious interaction with SSLVPN.

198.98.54[.]209

Attacker IP address that targeted FortiGate device and SSO login.

45.80.184[.]229

Attacker IP address that targeted FortiGate device and SSLVPN.

45.80.184[.]241

Attacker IP address that targeted FortiGate device and SSLVPN.

42.200.230[.]178

Attacker IP address that targeted FortiGate device and SSLVPN.

103.20.235[.]155

IP address identified in malicious authentications to SSO login.

104.28.227[.]105

IP address identified in attacker download of FortiGate configuration file.

Security updates for Wednesday

Post Syndicated from jzb original https://lwn.net/Articles/1066809/

Security updates have been issued by Debian (openssl), Fedora (corosync, goose, kea, pspp, and rauc), Mageia (python-pygments, roundcubemail, and tigervnc), SUSE (bind, gimp, google-cloud-sap-agent, govulncheck-vulndb, ignition, ImageMagick, python, python-PyJWT, and python-pyOpenSSL), and Ubuntu (adsys, juju-core, lxd, python-django, and salt).

From bytecode to bytes: automated magic packet generation

Post Syndicated from Axel Boesenach original https://blog.cloudflare.com/from-bpf-to-packet/

Linux malware often hides in Berkeley Packet Filter (BPF) socket programs, which are small bits of executable logic that can be embedded in the Linux kernel to customize how it processes network traffic. Some of the most persistent threats on the Internet use these filters to remain dormant until they receive a specific “magic” packet. Because these filters can be hundreds of instructions long and involve complex logical jumps, reverse-engineering them by hand is a slow process that creates a bottleneck for security researchers.

To find a better way, we looked at symbolic execution: a method of treating code as a series of constraints, rather than just instructions. By using the Z3 theorem prover, we can work backward from a malicious filter to automatically generate the packet required to trigger it. In this post, we explain how we built a tool to automate this, turning hours of manual assembly analysis into a task that takes just a few seconds.

The complexity ceiling

Before we look at how to deconstruct malicious filters, we need to understand the engine running them. The Berkeley Packet Filter (BPF) is a highly efficient technology that allows the kernel to pull specific packets from the network stack based on a set of bytecode instructions.

While many modern developers are familiar with eBPF (Extended BPF), the powerful evolution used for observability and security, this post focuses on “classic” BPF. Originally designed for tools like tcpdump, classic BPF uses a simple virtual machine with just two registers to evaluate network traffic at high speeds. Because it runs deep within the kernel and can “hide” traffic from user-space tools, it has become a favorite tool for malware authors looking to build stealthy backdoors.

Creating a contextual representation of BPF instructions using LLMs is already reducing the manual overhead for analysts, crafting the network packets that correspond to the validating condition can still be a lot of work, even with the added context provided by LLM’s.

Most of the time this is not a problem if your BPF program has only ~20 instructions, but this can get exponentially more complex and time-consuming when a BPF program consists of over 100 instructions as we’ve observed in some of the samples.

If we deconstruct the problem we can see that it boils down to reading a buffer and checking a constraint, depending on the outcome we either continue our execution path or stop and check the end result.

This kind of problem that has a deterministic outcome can be solved by Z3, a theorem prover that has the means to solve problems with a set of given constraints.

Exhibit A: BPFDoor

BPFDoor is a sophisticated, passive Linux backdoor, primarily used for cyberespionage by China-based threat actors, including Red Menshen (also known as Earth Bluecrow). Active since at least 2021, the malware is designed to maintain a stealthy foothold in compromised networks, targeting telecommunications, education, and government sectors, with a strong emphasis on operations in Asia and the Middle East.

BPFDoor uses BPF to monitor all incoming traffic without requiring a specific network port to be open. 

BPFDoor example instructions

Let’s focus on the sample of which was shared for the research done by Fortinet (82ed617816453eba2d755642e3efebfcbd19705ac626f6bc8ed238f4fc111bb0). If we dissect the BPF instructions and add some annotations, we can write the following:

(000) ldh [0xc]                   ; Read halfword at offset 12 (EtherType)
(001) jeq #0x86dd, jt 2, jf 6     ; 0x86DD (IPv6) -> ins 002 else ins 006
(002) ldb [0x14]                  ; Read byte at offset 20 (Protocol)
(003) jeq #0x11, jt 4, jf 15      ; 0x11 (UDP) -> ins 004 else DROP
(004) ldh [0x38]                  ; Read halfword at offset 56 (Dst Port)
(005) jeq #0x35, jt 14, jf 15     ; 0x35 (DNS) -> ACCEPT else DROP
(006) jeq #0x800, jt 7, jf 15     ; 0x800 (IPv4) -> ins 007 else DROP
(007) ldb [23]                    ; Read byte at offset 23 (Protocol)
(008) jeq #0x11, jt 9, jf 15      ; 0x11 (UDP) -> ins 009 else DROP
(009) ldh [20]                    ; Read halfword at offset 20 (fragment)
(010) jset #0x1fff, jt 15, jf 11  ; fragmented -> DROP else ins 011
(011) ldxb 4*([14]&0xf)           ; Load index (x) register ihl & 0xf
(012) ldh [x + 16]                ; Read halfword at offset x+16 (Dst Port)
(013) jeq #0x35, jt 14, jf 15     ; 0x35 (DNS) -> ACCEPT else DROP
(014) ret #0x40000 (ACCEPT)
(015) ret #0 (DROP)

In the above example we can establish there are two paths that lead to an ACCEPT outcome (step 5 and step 13). We can also clearly observe certain bytes being checked, including their offsets and values. 

Taking these validations, and keeping track of anything that would match the ACCEPT path, we should be able to automatically craft the packets for us.

Calculating the shortest path

To find the shortest path to a packet that validates the conditions presented in the BPF instructions, we need to keep track of paths that are not ending in the unfavorable condition.

We start off by creating a small queue. This queue holds several important data points:

  • The pointer to the next instruction.

  • Our current path of executed instructions + the next instruction.

Whenever we encounter an instruction that is checking a condition, we keep track of the outcome using a boolean and store this in our queue, so we can compare paths on the amount of conditions before the ACCEPT condition is reached and calculate our shortest path. In pseudocode we can express this best as:

paths = []
queue = dequeue([(0, [0])])

while queue:
	pc, path = queue.popleft()

	if pc >= len(instructions):
            continue

instruction = instructions[pc]
	
	if instruction.class == return_instruction:
		if instruction_constant != 0:  # accept
			paths.append(path)
		continue  # drop or accept, stop parsing this instruction

if instruction.class == jump_instruction:
	if instruction.operation == unconditional_jump:
		next_pc = pc + 1 + instruction_constant
		queue.append((next_pc, path + [next_pc]))
		continue

	# Conditional jump, explore both
	pc_true = pc + 1 + instruction.jump_true
	pc_false = pc + 1 + instruction.jump_false
	
	if instruction.jump_true <= instruction.jump_false:
		queue.append((pc_true, path + [pc_true]))
		queue.append((pc_false, path + [pc_false]))
	# else: same as above but reverse order of appending
# else: sequential instruction, append to the queue

If we execute this logic against our earlier BPFDoor example, we will be presented with the shortest path to an accepted packet:

(000) code=0x28 jt=0 jf=0  k=0xc     ; Read halfword at offset 12 (EtherType)
(001) code=0x15 jt=0 jf=4  k=0x86dd  ; IPv6 packet
(002) code=0x30 jt=0 jf=0  k=0x14    ; Read byte at offset 20 (Protocol)
(003) code=0x15 jt=0 jf=11 k=0x11    ; Protocol number 17 (UDP)
(004) code=0x28 jt=0 jf=0  k=0x38    ; Read word at offset 56 (Destination Port)
(005) code=0x15 jt=8 jf=9  k=0x35    ; Destination port 53
(014) code=0x06 jt=0 jf=0  k=0x40000 ; Accept

This is already a helpful automation in automatically solving our BPF constraints when it comes to analyzing BPF instructions and figuring out how the accepted packet for the backdoor would look. But what if we can take it a step further?

What if we could create a small tool that will give us the expected packet back in an automated manner?

Employing Z3 and scapy

One such tool that is perfect to solve problems given a set of constraints is Z3. Developed by Microsoft the tool is labeled as a theorem prover and exposes easy to use functions performing very complex mathematical operations under the hood.

The other tool we will use for crafting our valid magic packets is scapy, a popular Python library for interactive packet manipulation.

Given that we already have a way to figure out the path to an accepted packet, we are left with solving the problem by itself, and then translating this solution to the bytes at their respective offsets in a network packet.

Symbolic execution

A common technique for exploring paths taken in a given program is called symbolic execution. For this technique we are giving input that can be used as variables, including the constraints. By knowing the outcome of a successful path we can orchestrate our tool to find all of these successful paths and display the end result to us in a contextualized format.

For this to work we will need to implement a small machine capable of keeping track of the state of things like constants, registers, and different boolean operators as an outcome of a condition that is being checked.

class BPFPacketCrafter:
    MIN_PKT_SIZE = 64           # Minimum packet size (Ethernet + IP + UDP headers)
    LINK_ETHERNET = "ethernet"  # DLT_EN10MB - starts with Ethernet header
    LINK_RAW = "raw"            # DLT_RAW - starts with IP header directly
    MEM_SLOTS = 16              # Number of scratch memory slots (M[0] to M[15])

    def __init__(self, ins: list[BPFInsn], pkt_size: int = 128, ltype: str = "ethernet"):
        self.instructions = ins
        self.pkt_size = max(self.MIN_PKT_SIZE, pkt_size)
        self.ltype = ltype

        # Symbolic packet bytes
        self.packet = [BitVec(f"pkt_{i}", 8) for i in range(self.pkt_size)]

        # Symbolic registers (32-bit)
        self.A = BitVecVal(0, 32)  # Accumulator
        self.X = BitVecVal(0, 32)  # Index register

        # Scratch memory M[0-15] (32-bit words)
        self.M = [BitVecVal(0, 32) for _ in range(self.MEM_SLOTS)]

With the above code we’ve covered most of the machine for keeping a state during the symbolic execution. There are of course more conditions we need to keep track of, but these are handled during the solving process. To handle an ADD instruction, the machine maps the BPF operation to a Z3 addition:

def _execute_ins(self, insn: BPFInsn):
    cls = insn.cls
    if cls == BPFClass.ALU:
        op = insn.op
        src_val = BitVecVal(insn.k, 32) if insn.src == BPFSrc.K else self.X
        if op == BPFOp.ADD:
            self.A = self.A + src_val

Luckily the BPF instruction set is only a small set of instructions that’s relatively easy to implement — only having two registers to keep track of is definitely a welcome constraint!

The overall working of this symbolic execution can be laid out in the following abstracted overview:

  • Initialize the “x” (index) and “a” (accumulator) registers to their base state.

  • Loop over the instructions from the path that was identified as a successful path;

    • Execute non-jump instructions as-is, keeping track of register states.

    • Determine if a jump instruction is encountered, and check if the branch should be taken.

  • Use the Z3 check() function to check if our condition has been satisfied with the given constraint (ACCEPT).

  • Convert the Z3 bitvector arrays into bytes.

  • Use scapy to construct packets of the converted bytes.

If we look at the constraints build by the Z3 solver we can trace the execution steps taken by Z3 to build the packet bytes:

[If(Concat(pkt_12, pkt_13) == 0x800,
    pkt_14 & 0xF0 == 0x40,
    True),
 If(Concat(pkt_12, pkt_13) == 0x800, pkt_14 & 0x0F >= 5, True),
 If(Concat(pkt_12, pkt_13) == 0x800, pkt_14 & 0x0F == 5, True),
 If(Concat(pkt_12, pkt_13) == 0x86DD,
    pkt_14 & 0xF0 == 0x60,
    True),
 0x86DD == ZeroExt(16, Concat(pkt_12, pkt_13)),
 0x11 == ZeroExt(24, pkt_20),
 0x35 == ZeroExt(16, Concat(pkt_56, pkt_57))]

The first part of the Z3 displayed constraints are the constraints added to ensure we’re building up a valid ethernet IP when dealing with link-layer BPF instructions. The “If” statements apply specific constraints based on which protocol is detected:

  • IPv4 Logic (0x0800):

    • pkt_14 & 240 == 64: Byte 14 is the start of the IP header. The 0xF0 mask isolates the high nibble (the Version field) to check if the version is 4 (0x40).

    • pkt_14 & 15 == 5: 15 (0x0F), isolating the low nibble (IHL – Internet Header Length). This mandates a header length of 5 (20 bytes), which is the standard size without options.

  • IPv6 Logic (0x86dd):

    • pkt_14 & 240 == 0x60: Check if the version field is version 6 (0x60)

We can observe the network packet values when we look at the second part where different values are being checked:

  • 0x86DD: Packet condition for IPv6 header.

  • 0x11: UDP protocol number.

  • 0x35: The destination port (53).

Next to the expected values we can see the byte offset of where it should exist in a given packet (e.g. pkt_12, pkt_13).

Crafting packets

Now that we’ve established which bytes should exist at specific offsets we can convert it into an actual network packet using scapy. If we generate a new packet from the bytes of our previous Z3 constraints we can clearly see what our packet would look like, and store this for further processing:

###[ Ethernet ]###
  dst       = 00:00:00:00:00:00
  src       = 00:00:00:00:00:00
  type      = IPv6                 <-- IPv6 Packet
###[ IPv6 ]###
     version   = 6
     tc        = 0
     fl        = 0
     plen      = 0
     nh        = UDP               <-- UDP Protocol
     hlim      = 0
     src       = ::
     dst       = ::
###[ UDP ]###
        sport     = 0
        dport     = domain         <-- Port 53
        len       = 0
        chksum    = 0x0

These newly crafted packets can in turn be used for further research or identifying the presence of these implants by scanning for these over the network. 

Try it yourself

Understanding what a specific BPF set of instructions is doing can be cumbersome and time-consuming work. The example used is only a total of sixteen instructions, but we’ve encountered samples that were over 200 instructions that would’ve taken at least a day to understand. By using the Z3 solver, we can now reduce this time to just seconds, and not only display the path to an accepted packet, but also the packet skeleton for this as well.

We have open-sourced the filterforge tool to help the community automate the deconstruction of BPF-based implants. You can find the source code, along with usage examples, on our GitHub repository.

By publishing this research and sharing our tool for reducing analysts’ time spent figuring out the BPF instructions, we hope to spark further research by others to expand on this form of automation.

Python Supply-Chain Compromise

Post Syndicated from Bruce Schneier original https://www.schneier.com/blog/archives/2026/04/python-supply-chain-compromise.html

This is news:

A malicious supply chain compromise has been identified in the Python Package Index package litellm version 1.82.8. The published wheel contains a malicious .pth file (litellm_init.pth, 34,628 bytes) which is automatically executed by the Python interpreter on every startup, without requiring any explicit import of the litellm module.

There are a lot of really boring things we need to do to help secure all of these critical libraries: SBOMs, SLSA, SigStore. But we have to do them.

Как да разбираме воскръсналите (по Великден) словеса

Post Syndicated from original https://www.toest.bg/kak-da-razbirame-voskrusnalite-po-velikden-slovesa/

Как да разбираме воскръсналите (по Великден) словеса

Почти две хилядолетия ни делят от възкръсването на Божия Син. Това събитие е най-големият празник за православния свят (за католиците и протестантите е Рождество Христово) и дори хората, които не са толкова ревностни следовници на вярата, почитат традицията и ритуалите – най-малкото като боядисват яйца и правят (по-често купуват) козунаци.

Празниците, особено религиозните, идват със своя езиков антураж – думи и изрази с онази специфична характеристика, която лингвистите определят като архаичност, но тя е нещо повече. За кратко в съзнанието възкръсват формули, изгубили отчасти или напълно връзка със съвременната реч, с размито значение, граматически странности, особен привкус… Може би точно заради това са някак магични, а какво е празникът без малко магия?

Воистину воскресе!

Емблематични за Възкресение Христово са поздравът Христос воскресе! и отговорът Воистину воскресе! Вече в доста сайтове може да се намери информация за правилните варианти, макар че понякога в обясненията има известна доза съчинителство.

Правилността тук е условна, защото се определя спрямо правописа и граматиката на църковнославянския език, от който са наследени тези застинали във времето фрази. Като знаем, че в основата на църковнославянския е старобългарският¹, можем да научим малко повече и за далечното минало на нашия език. Преди хилядолетие правописът е следвал доста точно звученето на думите и днешните представки въз- и из- например са се пишели така, както са се изговаряли: въздрьжаниѥ, но въскрьсениѥ, изливати, но искоушати. Това е валидно и за църковнославянския език, но в представката въз-/въс- настъпва една фонетична промяна: гласната ъ преминава в о. Вариантите възкресе и возкресе представляват опити да се осъвремени и всъщност да се осмисли старинното воскресе – опити, които според мен трябва да срещат повече разбиране, отколкото критика.

Много спорове се вихрят около наречието воистину.

Според речниците на църковнославянския език думата е тази, а не воистина. Тя стъпва на старобългарското словосъчетание въ истинѫ, в което думата истина е във винителен падеж. В църковнославянския голямата носова гласна преминава в у и закономерно наречието придобива облика воистину², а воистина отново е опит за осъвременяване, както по-горе, но също и резултат от уподобяване с наистина.

По-интересно тук е значението на думата, която от някои се тълкува като ‘в името на истината, заради истината’. Такава семантика не откривам нито в старобългарските, нито в църковнославянските речници, макар че в тях са регистрирани разнообразни значения, например³: ‘справедливо, с право’ (Зная, Господи, че Твоите съдби са праведни, и по справедливост Ти ме наказа [Пс 118:17]); ‘истински, от сърце, от цялата душа’ (Няма да изостави Господ онези, които го обичат истински⁴; ‘право, вярно’ (Книжникът Му рече: добре, Учителю! Ти право каза, че Бог е един, и няма друг, освен Него [Марк 12:32]).

Едно от значенията на въ истинѫ/воистину е ‘наистина, действително, несъмнено’ и е засвидетелствано с доста употреби дори само в рамките на евангелските текстове. Ето един пример: А стотникът, като видя станалото, прослави Бога и рече: наистина, Тоя Човек е бил праведник [Лук 23:47]. Надявам се, вече е несъмнено, че в ответния поздрав Воистину воскресе! наречието следва да се разбира точно така.

Великден, Велика неделя, Разпети петък

Вместо да наричаме празника с църковното Възкресение Христово, употребяваме по-краткото название Великден. Оказва се, че то също е стародавно – още в Супрасълския сборник (Х век) е засвидетелствано с тази конкретна употреба. По същия начин наричат празника беларусите – Вяликьдзень, и украинците – Великдень, както и (неизненадващо) македонците – Велигден. В западнославянските езици пък велик е не денят, а нощта на възкресението.

Седмицата преди това е известна като Страстна, а също и като Велика неделя. Многократно е обяснявано и сигурно се знае от повечето образовани хора, че тук става въпрос не за горещи чувства и пламенни желания, а за страданията Христови по пътя му към кръстната смърт. Действително

старобългарската дума страсть много по-често се употребява с това значение – ‘мъка, страдание’, също и ‘мъченически подвиг’.

От нея има доста производни с оглед на ограничения брой старобългарски лексеми, за които знаем със сигурност (около 10 000), включително две сложни думи: страстоносьць и страстотрьпьць. И без да давам линк, ще се досетите, че те означават ‘мъченик, страдалец, човек, който понася страдания (в името на християнската вяра)’.

Думата страсть се е употребявала също в съвременния смисъл, само че е имала негативна конотация – така са се наричали най-вече плътските влечения, греховните телесни желания, които са изгаряли отвътре човека и е трябвало да бъдат обуздавани и побеждавани със силата на вярата.

Словосъчетанието Велика неделя като че ли се среща по-рядко от Страстната седмица, но е любопитно, защото в него личи остарялото вече значение на думата неделя. Още една лексема, която в миналото е била натоварена с различни значения – ‘седмица’ и ‘неделя, последният ден от седмицата’. Според Е. Френкел пренасянето на семантиката от названието на ден от седмицата върху цялата седмица е станало по модела на гръцкото τὰ σάββατα, тъй като съботният ден е бил символ на седмицата⁵.

Всеки ден от Страстната седмица съдържа определението велик: Велики понеделник, Велики вторник и т.н. Последният ден обикновено не се нарича Велика неделя, тъй като съвпада с Възкресение Христово. Петъкът обаче със сигурност прави изключение. Той често се определя като най-тъжния за християните ден, защото тогава Исус Христос изкупва с живота си греховете на човечеството. Разпети петък буквално означава „разпънатият петък“, а малко по-описателно – „петъкът, в който Христос е бил разпънат“. Първата дума в словосъчетанието представлява някогашното минало страдателно причастие распѧтыи, образувано от глагола распѧти ‘разпъна’. По-наблюдателните вече са забелязали, че за разлика от воскресе, тук не се съобразяваме с обеззвучаването на з в представката на думата и следваме съвременния правопис – разпети.

Още една интересна особеност има в това причастие. То е съхранило някогашната сложна (дълга) форма на прилагателните имена – распѧтыи. За сравнение, простата (кратката) е била распѧтъ (разпет). Тъй като вече има обяснение за разликата между двете форми, ще добавя само, че сложната се пази в членуваните прилагателни, причастия и числителни редни имена за мъжки род, единствено число. Пред определителния член има гласна и, която сигнализира именно за тези дълги форми: новият, вървящият, донесеният, третият. Ако бяха се запазили само кратките форми, сега вероятно щяхме да казваме и пишем новът, вървящът, донесенът, третът.

Разгледахме само няколко фрази и словосъчетания, характерни за Великден, а разяснихме около една четвърт от особеностите на старобългарския (и по-малко на църковнославянския) език. При това дори не засегнахме образуването на минало свършено време (воскресе) и на миналото страдателно причастие. Хиперболизирам, разбира се, но е факт, че в толкова ограничен брой думи се съдържа езикова история, която малко познаваме и чието познаване изобщо намираме за ценно.

По време на празниците – особено тези с вековни традиции – влизаме в по-различен речеви режим. Активизират се архаични езикови пластове, и то не само лексикални. До голяма степен фразите и думите, които употребяваме, са се превърнали във формули, използвани като езиков код. С него даваме сигнал, че временно сме в други, не-делнични измерения. Добре е обаче да имаме и ключ за този код, защото на човека поначало е свойствено да разгадава тайнствата, пък били те и празнични.

1 „Църковнославянският език е резултат от развитието на руската редакция на старобългарския език в периода XI–XVI в., в което намират отражение белези както на българския, така и на руския книжовен език през Средновековието.“ Кирило-Методиевска енциклопедия. Т. 4. Гл. ред. Л. Грашева. София: Академично издателство „М. Дринов“, 2003, с. 492.

2 В речниците на църковнославянския език наречието е с двойно н и в края има една особена буква, с която се бележи звукът у: воистиннꙋ. Ако се придържаме строго към църковнославянския правопис, би трябвало да пишем воистинну.

3 Примерите са взети от Старобългарски речник. Отг. ред. Д. Иванова-Мирчева. Т. 1. София: Васил Траянов, 1999, който е достъпен онлайн, и А. Бончев. Речник на църковнославянски език. Т. 1. София, 2002, с. 97. Представени са на съвременен български език според Синодалния превод на Библията. Съответствието на въ истинѫ/воистину е в получерен шрифт.

4 Примерът е от Супрасълския сборник, а преводът е мой.

5 Цит. по Български етимологичен речник. Т. 4. Ред. В. Георгиев, И. Дуриданов. София: Академично издателство „М. Дринов“, 2002, с. 598

Езикът може да е вкусен и извън блюдото – онзи, българският език, на който говорим от малки и на който около 24 май се кълнем в обич. А той в същността си е средство за общуване и за да ни служи добре, непрекъснато се променя. Да го погледнем в неговата динамика и да се опитаме да разберем какво става и защо, кои са движещите механизми и как те са свързани с обществените процеси. И тъй като задачата не е лека, ще го правим постепенно – на порции.

Staying Secure: An Inside Look at Zabbix Security Advisories

Post Syndicated from Michael Kammer original https://blog.zabbix.com/staying-secure-an-inside-look-at-zabbix-security-advisories/32831/

Security has always been a core priority for us at Zabbix. As part of our ongoing commitment to delivering a reliable and secure monitoring platform, we regularly publish security advisories that reflect both newly discovered vulnerabilities and the improvements we’ve made to address them.

These advisories are not just a list of issues – they are a direct result of continuous internal efforts to analyze, test, and strengthen every aspect of our product.

More than just fixes

Every vulnerability we disclose represents a deeper process behind the scenes. It involves:

  • Careful investigation and validation
  • Improvements to internal tooling and detection methods
  • Reevaluation of development and testing processes
  • Retesting to ensure robustness and prevent regressions

For us, security is not a one-time fix – it’s an ongoing cycle of improvement.

Decoding severity scores

We understand that some of the published severity scores may appear alarming at first glance. It’s important to note that these scores are based on worst-case scenario evaluations. In real-world deployments, the actual risk often depends on system configuration, network exposure, access controls, usage patterns, and more.

For many typical Zabbix installations, the effective risk level may be significantly lower than the maximum theoretical score suggests.

Stay updated – it matters

Keeping your Zabbix installation up to date is one of the most effective ways to maintain a secure environment.
Each update includes not only bug fixes, but also: security enhancements, hardening improvements, and stability and performance updates. By applying updates regularly, you make sure that your systems benefit from the latest protections. In short, staying up to date is a shared responsibility and the best defense.

Open communication

We are aware that security advisories can sometimes lead to external reports that frame vulnerabilities without full context. We want to be clear that:

  • Publishing advisories is a sign of maturity and transparency, not weakness
  • Proactively identifying and fixing issues is a core strength
  • Our goal is not to avoid disclosure, but to handle it responsibly and openly

Security is not about the absence of vulnerabilities. It’s about how quickly and effectively they are identified, addressed, and communicated.

Going forward

We believe that transparency builds trust. If you have any questions about Zabbix security advisories or best practices, we encourage you to reach out to us. Our team is always ready to clarify, assist, and provide guidance. We remain fully committed to improving Zabbix security at every level – from code to processes to communication.

Your trust is important to us, and we will continue to invest in making Zabbix a secure and dependable platform for your infrastructure.

The post Staying Secure: An Inside Look at Zabbix Security Advisories appeared first on Zabbix Blog.

The collective thoughts of the interwebz