A note from 2026: This article was published in 2018 and focuses on SAP hybris 6.6/6.7. The hybris branding has since been phased out in favor of SAP Commerce Cloud, and this specific Generic Audit bug was addressed in later patches and releases.

There is a new feature in hybris 6.6: Generic Audit. The new mechanism keeps track of modifications to attribute values of an auditable set of hybris objects. For this purpose, both the original value of the object and its new value are stored in the database for further inspection, if the need arises. According to the documentation, you can turn auditing on and off for particular types. For frequently changed objects, there is a risk that the system may consume a lot of database space over time, and the database itself may grow to a very large size. So, if you keep auditing on, you should keep these things under control.

Shortly after SAP hybris 6.6 was released, I found that this mechanism didn’t work well. Specifically, when all the audit.*.enabled=false settings are applied, there are still types that are audited anyway. Examples are Employee, Customer, and Product. Many people observed the same behavior, and the issue was reported to SAP. The bug has already been fixed, and, to my knowledge, SAP has released a patch. I haven’t received the patch yet, so I decided to investigate the issue in detail.

There is a global key, auditing.enabled, which turns the subsystem on and off. The issue is not reproduced if it is turned off via this key. However, if it is set to true, you may face the issue.

By default, hybris comes with the following setup:

# Audit blacklist
auditing.blacklist=itemsynctimestamp,joblog,logfile,jobmedia,task,taskcondition,processtasklog,cronjob,CronJobHistory

# Audit enabled item types
audit.user.enabled=true
audit.principalgrouprelation.enabled=true
audit.abstractcontactinfo.enabled=true
audit.address.enabled=true
audit.cart.enabled=true
audit.cartentry.enabled=true
audit.country.enabled=true
audit.currency.enabled=true
audit.order.enabled=true
audit.orderentry.enabled=true
audit.paymentinfo.enabled=true
audit.paymentmode.enabled=true

audit.product.enabled=true
audit.quote.enabled=true
audit.quoteentry.enabled=true

audit.region.enabled=true
audit.title.enabled=true
audit.unit.enabled=true
audit.usergroup.enabled=true
audit.b2bunit.enabled=true
audit.sapb2bdocument.enabled=true
audit.partneraddress.enabled=true
audit.userpasswordchangeaudit.enabled=true
audit.cxusertosegment.enabled=true
audit.cxsegment.enabled=true
audit.btgsegmentresult.enabled=true
audit.btgsegment.enabled=true
audit.consent.enabled=true
audit.consenttemplate.enabled=true
audit.city.enabled=true
audit.district.enabled=true
audit.csticket.enabled=true
audit.comment.enabled=true
audit.employee.enabled=true
audit.csagentgroup.enabled=true
audit.basesite.enabled=true
audit.saporder.enabled=true
audit.customerreview.enabled=true
audit.language.enabled=true

For example, the last line says that any changes in Language will be stored. There is a table, languages32sn, which contains the operation details, such as the operation type, two states of the object before and after the operation, and the user ID of the user who made the change.

Generic Audit database table with audit records

If you set audit.XXXXX.enabled=false, this mechanism should stop working for the type XXXXX. This is true for Language or BaseSite, but, as reported, “it won’t work for Employee, Customer and Product.”

In fact, this statement is not 100% correct.

How it really works

If you decide to turn auditing off for Employee via the following configuration:

audit.Employee.enabled=false

the system checks all supertypes of Employee, and if it finds any, it checks whether these types are in the configuration. This is both bad design and a bug at the same time. The bad design lies in the fact that

auditEnablementService.isAuditEnabledForType(<type>)

silently changes the configuration based on undocumented and non-transparent logic: checking the supertypes and returning true for some combinations. At minimum, the system should report the inconsistency in the log rather than silently changing the settings.

As for the bug: what is important is that the settings for these supertypes are not taken into account, only their mere existence. For example, the following fragment will print true true true false:

//groovy script, try it in HAC
cs=configurationService.getConfiguration();
cs.setProperty("audit.User.enabled", "true");
cs.setProperty("audit.Employee.enabled", "false");
auditEnablementService.refreshConfiguredAuditTypes();
//next line is true
println(auditEnablementService.isAuditEnabledForType("Employee"));
cs=configurationService.getConfiguration();
cs.setProperty("audit.User.enabled", "false");
cs.setProperty("audit.Employee.enabled", "false");
auditEnablementService.refreshConfiguredAuditTypes();
//next line is true
println(auditEnablementService.isAuditEnabledForType("Employee"));
cs=configurationService.getConfiguration();
cs.setProperty("audit.User.enabled", "something");
cs.etProperty("audit.Employee.enabled", "false");
auditEnablementService.refreshConfiguredAuditTypes();
//next line is true
println(auditEnablementService.isAuditEnabledForType("Employee"));
cs=configurationService.getConfiguration();
cs.clearProperty("audit.User.enabled");
cs.setProperty("audit.Employee.enabled", "false");
auditEnablementService.refreshConfiguredAuditTypes();
//next line is true
println(auditEnablementService.isAuditEnabledForType("Employee"));

In this fragment, I demonstrate that audit.User.enabled affects audit.Employee.enabled without taking into account which value is specified for User auditing.

The JIRA ticket from SAP also reports that there is an issue with the Product object too. This is not completely true. The roots of the problem are the same. You will have issues with all subtypes of the Product type, such as VariantType or ApparelProduct. Actually, it extends to any other subtypes of the specified types.

The following example shows that VariantProduct, a subtype of Product, won’t be audited only if the Product setting is removed:

cs=configurationService.getConfiguration();
cs.setProperty("audit.Product.enabled", "false");
auditEnablementService.refreshConfiguredAuditTypes();
//next line is false
println(auditEnablementService.isAuditEnabledForType("Product"));
cs=configurationService.getConfiguration();
cs.setProperty("audit.Product.enabled", "true");
cs.setProperty("audit.VariantProduct.enabled", "false");
auditEnablementService.refreshConfiguredAuditTypes();
//next line is true
println(auditEnablementService.isAuditEnabledForType("VariantProduct"));
cs=configurationService.getConfiguration();
cs.setProperty("audit.Product.enabled", "false");
cs.setProperty("audit.VariantProduct.enabled", "false");
auditEnablementService.refreshConfiguredAuditTypes();
//next line is true
println(auditEnablementService.isAuditEnabledForType("VariantProduct"));
cs=configurationService.getConfiguration();
cs.setProperty("audit.Product.enabled", "something");
cs.setProperty("audit.VariantProduct.enabled", "false");
auditEnablementService.refreshConfiguredAuditTypes();
//next line is true
println(auditEnablementService.isAuditEnabledForType("VariantProduct"));
cs=configurationService.getConfiguration();
cs.clearProperty("audit.Product.enabled");
cs.setProperty("audit.VariantProduct.enabled", "false");
auditEnablementService.refreshConfiguredAuditTypes();
//next line is false
println(auditEnablementService.isAuditEnabledForType("VariantProduct")); //false